Egress IP Family Policy (IPv4/IPv6) (Español)
Tabla de contenidos
Sección titulada «Tabla de contenidos»- Qué es
- Por qué existe
- Los tres valores
- Cómo configurarla
- Cómo se resuelve
auto - Cómo se aplican
ipv4/ipv6 - Compatibilidad con SOCKS5
- Comportamiento de fallo cerrado
- Modelo de datos
- Documentación relacionada
Cada proxy del registro tiene un campo family con tres valores posibles, validados mediante una enumeración de Zod:
family: z.enum(["auto", "ipv4", "ipv6"]).optional().default("auto"),El valor predeterminado del campo es "auto", lo que conserva el comportamiento anterior de pila dual. Establecerlo en ipv4 o ipv6 fija la familia de conexión para ese proxy.
La directiva se normaliza en todas partes mediante una única función auxiliar, de modo que cualquier valor desconocido se convierte en auto:
export type ProxyFamily = "auto" | "ipv4" | "ipv6";
export function parseProxyFamily(value: unknown): ProxyFamily { return value === "ipv4" || value === "ipv6" ? value : "auto";}Por qué existe
Sección titulada «Por qué existe»Se introdujo en el PR #3777. Los problemas que lo motivaron fueron:
| Problema | Qué soluciona la directiva |
|---|---|
| La salida exclusiva por IPv6 se filtra a IPv4 | Cuando un host proxy tiene registros A y AAAA (o el sistema operativo prefiere IPv4), Happy Eyeballs puede establecer la salida mediante IPv4 aunque se pretenda usar una ruta exclusiva por IPv6. Fijar ipv6 elimina esa filtración. |
| Revocación por anomalías de salida compartida | Los proveedores con rotación (codex/openai) revocan tokens cuando muchas cuentas salen a través de la misma IP con un volumen elevado. Controlar la familia de salida ayuda a mantener las cuentas en rutas de salida distintas y predecibles (consulta src/lib/proxyEgress.ts para ver los diagnósticos de IP de salida que complementan esta función). |
| Salida determinista para cumplimiento normativo/pruebas | Cuando se debe garantizar que el tráfico salga mediante una familia específica, auto no es suficiente. |
La directiva es intencionadamente por proxy, no global: distintos proxies del grupo pueden tener políticas diferentes.
Los tres valores
Sección titulada «Los tres valores»| Valor | Etiqueta de la IU | Comportamiento |
|---|---|---|
auto |
Auto (dual-stack) |
El SO elige la familia. Para un host proxy que sea un literal de IP, la familia es intrínseca al literal; para un nombre de host, ambas familias son válidas. Este es el valor predeterminado. |
ipv4 |
IPv4 only |
Restringe la conexión a IPv4. Falla de forma segura si el host proxy no tiene ningún registro IPv4 (A). |
ipv6 |
IPv6 only |
Restringe la conexión a IPv6. Falla de forma segura si el host proxy no tiene ningún registro IPv6 (AAAA). |
Las cadenas de la IU se encuentran en src/i18n/messages/en.json (labelFamily, familyAuto, familyIpv4, familyIpv6, familyHint).
Cómo configurarlo
Sección titulada «Cómo configurarlo»Panel de control
Sección titulada «Panel de control»El selector se encuentra en el formulario de proxy de la pestaña Proxy Pool:
- Abra Dashboard → Settings → Proxy → Proxy Pool
- Añada o edite un proxy
- Establezca el menú desplegable IP family en
Auto (dual-stack),IPv4 onlyoIPv6 only - Guarde los cambios
El control lo renderiza ProxyRegistryManager.tsx (montado en proxy/ProxyPoolTab.tsx).
El campo family forma parte de las cargas útiles para crear o actualizar el registro de proxies, se valida mediante createProxyRegistrySchema / updateProxyRegistrySchema (src/shared/validation/schemas.ts) y lo gestionan POST / PATCH /api/v1/management/proxies:
# Crear un proxy exclusivo para IPv6curl -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" }'
# Cambiar un proxy existente para que use exclusivamente IPv4curl -X PATCH http://localhost:20128/api/v1/management/proxies \ -H "Content-Type: application/json" \ -d '{ "id": "proxy-uuid-here", "family": "ipv4" }'El objeto de configuración de proxy en línea utilizado para las entradas de proxy ascendente también acepta el mismo campo (upstream_proxy_config.family; consulte el Modelo de datos).
Para consultar el resto de la API de CRUD y asignación de proxies, consulte PROXY_GUIDE.md.
Cómo se resuelve auto
Sección titulada «Cómo se resuelve auto»Cuando family es auto, OmniRoute no añade ninguna directiva: la URL del proxy se utiliza tal cual y la familia de conexión se determina de forma intrínseca.
Al crear la URL (proxyConfigToUrl / normalizeProxyUrl en open-sse/utils/proxyDispatcher.ts), un proxy auto genera una URL simple sin ningún marcador:
const fam = parseProxyFamily(config.family);const normalized = normalizeProxyUrl(proxyUrlStr, "context proxy", { allowSocks5,});return fam === "auto" ? normalized : `${normalized}?family=${fam}`;Al realizar el envío (resolveDispatcherFamily), auto se resuelve como la familia intrínseca de un host que sea un literal de IP, o como null (dejar que el SO decida) en el caso de un nombre de host:
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 para un nombre de host → el SO elige // ...}Por tanto:
auto+ host que sea un literal de IP (192.0.2.1/[2001:db8::1]) → familia de ese literal.auto+ nombre de host →null→ resolución estándar de doble pila del SO.
Cómo se aplican ipv4 / ipv6
Sección titulada «Cómo se aplican ipv4 / ipv6»Una directiva distinta de auto se transmite como un único marcador de consulta sintético —?family=ipv4 o ?family=ipv6— que se añade una sola vez a la URL normalizada del proxy. normalizeProxyUrl se asegura de eliminar y volver a añadir este marcador exactamente una vez, para que nunca corrompa el análisis del puerto.
Cuando se construye el dispatcher, el marcador se lee y se convierte en una familia de conexión concreta. Si el host es un literal de IP de la familia opuesta, OmniRoute lanza un error (las contradicciones se gestionan mediante cierre seguro):
const want = directive === "ipv6" ? 6 : 4;if (literal !== null && literal !== want) { throw new Error( `[ProxyDispatcher] La directiva de familia del proxy ${directive} contradice el host literal ${literal === 6 ? "IPv6" : "IPv4"}` );}A continuación, la familia concreta se fija en el conector:
- Proxies HTTP/HTTPS (
ProxyAgent):proxyTls: { family, autoSelectFamily: false }— desactiva Happy Eyeballs para que la familia elegida sea la única con la que se intente establecer la conexión. - Proxies SOCKS5: un conector personalizado pasa
socket_options: { family, autoSelectFamily: false }al cliente SOCKS (consulte Compatibilidad con SOCKS5).
Compatibilidad con SOCKS5
Sección titulada «Compatibilidad con SOCKS5»La fijación de familia funciona con proxies SOCKS5, pero la versión estándar de fetch-socks no expone las opciones de socket necesarias para fijar la familia del salto del proxy. OmniRoute incluye su propio conector para ello:
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 {};}Todos los envíos mediante SOCKS5 pasan por createSocksDispatcherWithFamily, independientemente de family (incluidos null / auto sobre un nombre de host): buildSocksFamilySocketOptions(null) produce {}, y se utiliza la misma ruta SocksClient.createConnection + TLS buildConnector, con la fijación mediante socket_options, para que Happy Eyeballs no pueda elegir IPv4 en una política de salida exclusiva para IPv6.
La compatibilidad con SOCKS5 está activada de forma predeterminada (puede desactivarse mediante ENABLE_SOCKS5_PROXY=false); consulte PROXY_GUIDE.md → Variables de entorno.
Comportamiento de cierre seguro
Sección titulada «Comportamiento de cierre seguro»El objetivo de la directiva es rechazar la conexión en lugar de recurrir silenciosamente a la familia incorrecta. Dos comprobaciones garantizan este comportamiento:
-
Contradicción de literal — una directiva que contradiga un host expresado como literal de IP provoca un error durante la construcción del dispatcher (
resolveDispatcherFamily, mostrado anteriormente). -
Comprobación DNS preliminar del nombre de host — para un proxy con nombre de host y una familia fijada,
proxyFetch.tsverifica que el nombre de host tenga realmente un registro de la familia requerida antes de iniciar la salida, medianteassertHostnameSupportsFamily:open-sse/utils/proxyFamilyResolve.ts const hasFamily = records.some((r) => r.family === family);if (!hasFamily) {throw new Error(`[ProxyFamily] El host del proxy ${host} no tiene ningún registro ${family === 6 ? "IPv6 (AAAA)" : "IPv4 (A)"}; ` +`se rechaza la salida exclusiva para ${family === 6 ? "IPv6" : "IPv4"} (cierre seguro)`);}En caso de error,
proxyFetch.tsetiqueta el error concode = "PROXY_FAMILY_UNAVAILABLE"ystatusCode = 503. Un error de resolución DNS también se trata mediante cierre seguro (se rechaza la salida).
La comprobación DNS preliminar no realiza ninguna operación para los hosts expresados como literales de IP: su familia es intrínseca y no requiere ninguna consulta.
Modelo de datos
Sección titulada «Modelo de datos»La columna family se añadió mediante la migración 099_proxy_family.sql a dos tablas:
-- src/lib/db/migrations/099_proxy_family.sqlALTER 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— la directiva por proxy para las entradas del registro (src/lib/db/proxies.ts). Las consultas de resolución seleccionanfamilyjunto con las demás columnas del proxy, y un valor ausente o que no sea una cadena se convierte en"auto".upstream_proxy_config.family— la directiva para las entradas de proxy ascendente (src/lib/db/upstreamProxy.ts), con el mismo valor predeterminado"auto".
Cuando un objeto de proxy resuelto contiene un valor de family distinto de auto, proxyConfigToUrl añade el marcador ?family= para que la configuración fijada llegue intacta hasta el dispatcher.
Documentación relacionada
Sección titulada «Documentación relacionada»📖 Documentación relacionada:
- Guía de proxies — sistema completo de proxies: CRUD del registro, resolución en 4 niveles, rotación, comprobaciones de estado y referencia de la API
docs/security/STEALTH_GUIDE.md(git; no se compila en/docs) — capas de huella digital TLS y de la CLI que funcionan sobre el proxy- Niveles de protección de rutas — aplicación obligatoria de loopback para rutas exclusivamente locales
HagiCode
HagiCode es un espacio de trabajo de programación con agentes, flujos estructurados, ejecución multiagente y vistas de Hero Dungeon.
Convierte ideas en software útil con un flujo de trabajo con agentes más inteligente, rápido y ameno.

- SmartLos flujos estructurados convierten la intención en un itinerario ejecutable desde la idea hasta la entrega.
- EfficientLos flujos multiagente permiten avanzar en paralelo con la investigación, implementación y revisión.
- FunHero Dungeon hace que las largas sesiones de programación sean visuales y colaborativas.