* feat(docs): mirror every docs/ page in all 65 locales Extends the documentation mirrors from the 22-page core set (#13940) to every Markdown page under docs/: 152 sources x 65 locales = 9,880 mirrors (6,208 new), language bars rewritten for the full locale list, state adopted so the blocking drift gate now covers all 152 pages. run-translation.mjs: an oversized block made only of table rows or list items (PROVIDER_REFERENCE.md 244-row table, FREE_TIERS.md 71-item list) is cut at item boundaries and rejoined without a blank line — the single 16-40 KB request outlived the backend socket for verbose scripts. 48 older mirrors whose tables had lost rows were retranslated with --force. * docs(i18n): refresh mirrors for the sources the base changed since the branch cut Section-level retranslation of the 29 docs (and README.md) whose source or mirrors moved on release/v3.8.51 during the run, then state adoption; the drift gate is green again on the merged tree.
17 KiB
Egress IP Family Policy (IPv4/IPv6) (Polski)
🌐 Languages: 🇺🇸 English · 🇪🇹 am · 🇸🇦 ar · 🇦🇿 az · 🇧🇬 bg · 🇧🇩 bn · 🇨🇿 cs · 🇩🇰 da · 🇩🇪 de · 🇬🇷 el · 🇪🇸 es · 🇪🇪 et · 🇮🇷 fa · 🇫🇮 fi · 🇫🇷 fr · 🇮🇪 ga · 🇮🇳 gu · 🇳🇬 ha · 🇮🇱 he · 🇮🇳 hi · 🇭🇷 hr · 🇭🇺 hu · 🇦🇲 hy · 🇮🇩 id · 🇳🇬 ig · 🇮🇹 it · 🇯🇵 ja · 🇬🇪 ka · 🇰🇭 km · 🇮🇳 kn · 🇰🇷 ko · 🇱🇹 lt · 🇱🇻 lv · 🇮🇳 ml · 🇮🇳 mr · 🇲🇾 ms · 🇲🇹 mt · 🇲🇲 my · 🇳🇵 ne · 🇳🇱 nl · 🇳🇴 no · 🇮🇳 or · 🇮🇳 pa · 🇵🇭 phi · 🇵🇹 pt · 🇧🇷 pt-BR · 🇷🇴 ro · 🇷🇺 ru · 🇱🇰 si · 🇸🇰 sk · 🇸🇮 sl · 🇷🇸 sr · 🇸🇪 sv · 🇰🇪 sw · 🇮🇳 ta · 🇮🇳 te · 🇹🇭 th · 🇹🇷 tr · 🇺🇦 uk-UA · 🇵🇰 ur · 🇺🇿 uz · 🇻🇳 vi · 🇳🇬 yo · 🇨🇳 zh-CN · 🇹🇼 zh-TW
title: "Polityka rodziny IP egress (IPv4/IPv6)" version: 3.8.40 lastUpdated: 2026-06-28
Polityka rodziny IP egress (IPv4/IPv6)
Przypnij ruch wychodzący do jednej rodziny IP —
auto,ipv4lubipv6— per proxy, żeby egress tylko-IPv6 nigdy cicho nie wyciekał z powrotem na IPv4.
Source of truth:
open-sse/utils/proxyFamily.ts,open-sse/utils/proxyDispatcher.ts,open-sse/utils/proxyFetch.ts,open-sse/utils/socksConnectorWithFamily.ts,open-sse/utils/proxyFamilyResolve.ts,src/shared/validation/schemas.ts,src/lib/db/proxies.ts,src/lib/db/upstreamProxy.ts,src/lib/db/migrations/099_proxy_family.sql
OmniRoute pozwala każdemu proxy nieść dyrektywę egress rodziny adresów. Domyślnie system operacyjny wybiera IPv4 lub IPv6 (dual-stack, „Happy Eyeballs”). Gdy ustawisz dyrektywę na ipv4 lub ipv6, OmniRoute przypina każde połączenie przez to proxy do wybranej rodziny i fails closed (odmawia), zamiast robić fallback na drugą rodzinę.
Ta strona dokumentuje, czym jest dyrektywa, po co istnieje, gdzie się ją konfiguruje i jak runtime ją rozwiązuje.
Spis treści
- Czym to jest
- Dlaczego istnieje
- Trzy wartości
- Jak to skonfigurować
- Jak rozwiązuje się
auto - Jak egzekwowane są
ipv4/ipv6 - Kompatybilność SOCKS5
- Zachowanie fail-closed
- Model danych
- Powiązana dokumentacja
Czym to jest
Każde proxy w rejestrze ma pole family z trzema możliwymi wartościami, walidowanymi przez enum Zod:
// src/shared/validation/schemas.ts
family: z.enum(["auto", "ipv4", "ipv6"]).optional().default("auto"),
Pole domyślnie ma wartość "auto", co zachowuje wcześniejsze zachowanie dual-stack. Ustawienie na ipv4 lub ipv6 przypina rodzinę połączenia (connect family) dla tego proxy.
Dyrektywa jest normalizowana wszędzie przez jeden helper, więc dowolna nieznana wartość zwija się do auto:
// open-sse/utils/proxyFamily.ts
export type ProxyFamily = "auto" | "ipv4" | "ipv6";
export function parseProxyFamily(value: unknown): ProxyFamily {
return value === "ipv4" || value === "ipv6" ? value : "auto";
}
Dlaczego istnieje
Wprowadzone w PR #3777. Problemy motywujące:
| Problem | Co naprawia dyrektywa |
|---|---|
| Egress tylko-IPv6 wyciekający na IPv4 | Gdy host proxy ma zarówno rekordy A, jak i AAAA (albo OS preferuje IPv4), Happy Eyeballs może nawiązać połączenie po IPv4 nawet gdy zamierzasz ścieżkę tylko-IPv6. Przypięcie ipv6 usuwa ten wyciek. |
| Revocation przy anomalii shared-egress | Rotujące providery (codex/openai) unieważniają tokeny, gdy wiele kont wychodzi przez ten sam IP przy wysokim wolumenie. Kontrola rodziny egress jest częścią utrzymania kont na odrębnych, przewidywalnych ścieżkach egress (zob. src/lib/proxyEgress.ts pod kątem diagnostyki egress-IP, która idzie w parze z tym). |
| Deterministyczny egress na compliance/testy | Gdy musisz zagwarantować, że ruch wychodzi określoną rodziną, auto nie wystarcza. |
Dyrektywa jest celowo per-proxy, a nie globalna — różne proxy w puli mogą mieć różne polityki.
Trzy wartości
| Wartość | Etykieta UI | Zachowanie |
|---|---|---|
auto |
Auto (dual-stack) |
OS wybiera rodzinę. Dla hosta proxy będącego literałem IP rodzina wynika z literału; dla hostname obie rodziny są dopuszczalne. To domyślna wartość. |
ipv4 |
IPv4 only |
Przypina połączenie do IPv4. Fails closed, jeśli host proxy nie ma rekordu IPv4 (A). |
ipv6 |
IPv6 only |
Przypina połączenie do IPv6. Fails closed, jeśli host proxy nie ma rekordu IPv6 (AAAA). |
Stringi UI są w src/i18n/messages/en.json (labelFamily, familyAuto, familyIpv4, familyIpv6, familyHint).
Jak to skonfigurować
Dashboard
Selektor jest w formularzu proxy zakładki Proxy Pool:
- Otwórz Dashboard → Settings → Proxy → Proxy Pool
- Dodaj lub edytuj proxy
- Ustaw dropdown IP family na
Auto (dual-stack),IPv4 onlylubIPv6 only - Zapisz
Kontrolka jest renderowana przez ProxyRegistryManager.tsx (montowany w proxy/ProxyPoolTab.tsx).
API
Pole family jest częścią payloadów create/update rejestru proxy, walidowanych przez createProxyRegistrySchema / updateProxyRegistrySchema (src/shared/validation/schemas.ts) i obsługiwanych przez POST / PATCH /api/v1/management/proxies:
# Create an IPv6-only proxy
curl -X POST http://localhost:20128/api/v1/management/proxies \
-H "Content-Type: application/json" \
-d '{
"name": "IPv6 egress",
"type": "socks5",
"host": "proxy.example.com",
"port": 1080,
"family": "ipv6"
}'
# Change an existing proxy to IPv4-only
curl -X PATCH http://localhost:20128/api/v1/management/proxies \
-H "Content-Type: application/json" \
-d '{ "id": "proxy-uuid-here", "family": "ipv4" }'
To samo pole jest też akceptowane przez inline obiekt konfiguracji proxy używany przy wpisach upstream-proxy (upstream_proxy_config.family, zob. Model danych).
Reszta API CRUD/assignment proxy: PROXY_GUIDE.md.
Jak rozwiązuje się auto
Gdy family to auto, OmniRoute nie dokleja żadnej dyrektywy — URL proxy jest używany as-is, a rodzina połączenia wynika wewnętrznie.
W czasie budowy URL (proxyConfigToUrl / normalizeProxyUrl w open-sse/utils/proxyDispatcher.ts) proxy auto daje zwykły URL bez markera:
// open-sse/utils/proxyDispatcher.ts
const fam = parseProxyFamily(config.family);
const normalized = normalizeProxyUrl(proxyUrlStr, "context proxy", {
allowSocks5,
});
return fam === "auto" ? normalized : `${normalized}?family=${fam}`;
W czasie dispatchu (resolveDispatcherFamily) auto rozwiązuje się do wewnętrznej rodziny hosta będącego literałem IP albo do null (decyduje OS) dla hostname:
// open-sse/utils/proxyDispatcher.ts
function resolveDispatcherFamily(parsed: URL): 4 | 6 | null {
const directive = parseProxyFamily(parsed.searchParams.get("family") ?? undefined);
const literal = detectIpLiteralFamily(parsed.hostname);
if (directive === "auto") return literal; // null for a hostname → OS picks
// ...
}
Zatem:
auto+ host literał IP (192.0.2.1/[2001:db8::1]) → rodzina tego literału.auto+ hostname →null→ standardowa dual-stack rezolucja OS.
Jak egzekwowane są ipv4 / ipv6
Dyrektywa inna niż auto podróżuje jako jeden syntetyczny marker query — ?family=ipv4 lub ?family=ipv6 — doklejany raz do znormalizowanego URL proxy. normalizeProxyUrl ostrożnie usuwa i ponownie dokleja ten marker dokładnie raz, żeby nigdy nie psuć parsowania portu.
Gdy budowany jest dispatcher, marker jest odczytywany i zamieniany na konkretną rodzinę połączenia. Jeśli host to literał IP przeciwnej rodziny, OmniRoute rzuca wyjątek (sprzeczność = fail-closed):
// open-sse/utils/proxyDispatcher.ts
const want = directive === "ipv6" ? 6 : 4;
if (literal !== null && literal !== want) {
throw new Error(
`[ProxyDispatcher] Proxy family directive ${directive} contradicts ${literal === 6 ? "IPv6" : "IPv4"} literal host`
);
}
Konkretna rodzina jest potem przypinana na connectorze:
- Proxy HTTP/HTTPS (
ProxyAgent):proxyTls: { family, autoSelectFamily: false }— wyłącza Happy Eyeballs, więc wybierana jest wyłącznie wskazana rodzina. - Proxy SOCKS5: niestandardowy connector przekazuje
socket_options: { family, autoSelectFamily: false }do klienta SOCKS (zob. Kompatybilność SOCKS5).
Kompatybilność SOCKS5
Pin rodziny działa z proxy SOCKS5, ale stockowe fetch-socks nie udostępnia opcji socket potrzebnych do przypięcia rodziny hopu proxy. OmniRoute dostarcza własny connector do tego:
// open-sse/utils/socksConnectorWithFamily.ts
export function buildSocksFamilySocketOptions(family: 4 | 6 | null): Record<string, unknown> {
if (family === 6) return { family: 6, autoSelectFamily: false };
if (family === 4) return { family: 4, autoSelectFamily: false };
return {};
}
Wszystkie dispatchery SOCKS5 przechodzą przez createSocksDispatcherWithFamily niezależnie od family (również null / auto nad hostname): buildSocksFamilySocketOptions(null) daje {}, a ta sama ścieżka SocksClient.createConnection + TLS buildConnector jest używana z przypięciem socket_options, żeby Happy Eyeballs nie wybrał IPv4 przy polityce egress tylko-IPv6.
Sam support SOCKS5 jest domyślnie włączony (opt-out przez ENABLE_SOCKS5_PROXY=false); zob. PROXY_GUIDE.md → Environment Variables.
Zachowanie fail-closed
Cały sens dyrektywy to odmowa, a nie cichy fallback na złą rodzinę. Egzekwują to dwa guardy:
-
Sprzeczność literału — dyrektywa sprzeczna z hostem będącym literałem IP rzuca wyjątek przy budowie dispatchera (
resolveDispatcherFamily, pokazane wyżej). -
Pre-flight DNS hostname — dla proxy z hostname i przypiętą rodziną
proxyFetch.tsweryfikuje, że hostname faktycznie ma rekord w wymaganej rodzinie przed egressem, przezassertHostnameSupportsFamily:// open-sse/utils/proxyFamilyResolve.ts const hasFamily = records.some((r) => r.family === family); if (!hasFamily) { throw new Error( `[ProxyFamily] Proxy host ${host} has no ${family === 6 ? "IPv6 (AAAA)" : "IPv4 (A)"} record; ` + `refusing ${family === 6 ? "IPv6" : "IPv4"}-only egress (fail-closed)` ); }Przy niepowodzeniu
proxyFetch.tsoznacza błąd jakocode = "PROXY_FAMILY_UNAVAILABLE"istatusCode = 503. Niepowodzenie rezolucji DNS jest również traktowane jako fail-closed (odmowa egressu).
Hosty będące literałami IP to no-op dla pre-flight DNS — ich rodzina wynika z literału i nie wymaga lookupu.
Model danych
Kolumna family została dodana migracją 099_proxy_family.sql do dwóch tabel:
-- src/lib/db/migrations/099_proxy_family.sql
ALTER TABLE proxy_registry ADD COLUMN family TEXT NOT NULL DEFAULT 'auto';
ALTER TABLE upstream_proxy_config ADD COLUMN family TEXT NOT NULL DEFAULT 'auto';
proxy_registry.family— dyrektywa per-proxy dla wpisów rejestru (src/lib/db/proxies.ts). Zapytania rezolucji wybierająfamilyobok pozostałych kolumn proxy, a brakująca/nie-stringowa wartość jest coercowana do"auto".upstream_proxy_config.family— dyrektywa dla wpisów upstream-proxy (src/lib/db/upstreamProxy.ts), z tym samym domyślnym"auto".
Gdy rozwiązany obiekt proxy niesie nie-auto family, proxyConfigToUrl dokleja marker ?family=, żeby pin przetrwał aż do dispatchera.
Powiązana dokumentacja
📖 Powiązana dokumentacja:
- Przewodnik po proxy — kompletny system proxy: operacje CRUD rejestru, 4-poziomowe rozpoznawanie, rotacja, sprawdzanie kondycji, dokumentacja API
docs/security/STEALTH_GUIDE.md(git; nie jest kompilowany do/docs) — warstwy odcisku palca TLS i odcisku palca CLI działające na bazie proxy- Poziomy ochrony tras — wymuszanie dostępu przez interfejs loopback dla tras dostępnych wyłącznie lokalnie