Tema representativo de entrevista

Entrevista técnica: ¿Cómo corrige el análisis de hostport de Go 1.25 la construcción de direcciones IPv6?

CodingIntermedio
Equipo editorial de Offer.ccPublicado Actualizado

Pregunta

El código construye una dirección para net.Dial con fmt.Sprintf("%s:%d", host, port). Explica por qué falla con IPv6, corrígelo con net.JoinHostPort y diseña pruebas para IPv4, IPv6, zonas y puertos inválidos.

Enunciado y contexto

Un servicio lee host y puerto desde la configuración y pasa fmt.Sprintf("%s:%d", host, port) a net.Dial. Las pruebas de IPv4 pasan, pero producción expone IPv6, direcciones link-local y análisis de puertos malformados. Corrige la implementación en Go 1.25, explica net.JoinHostPort, SplitHostPort, los identificadores de zona y los límites de validación de entrada, y analiza el nuevo analizador go vet hostport. La habilidad principal es la programación de red portable, por lo que esta es una pregunta de coding.

Qué evalúa el entrevistador

Primero, si reconoces que el texto IPv6 contiene múltiples dos puntos, lo que hace que una concatenación simple como 2001:db8::1:443 sea ambigua.

Segundo, si utilizas la biblioteca estándar para agregar corchetes según la sintaxis de direcciones de red en lugar de ramas condicionales escritas a mano.

Tercero, si distingues entre una cadena de host, un identificador de zona, una cadena de puerto y una autoridad completa para que no se dupliquen los corchetes ni el análisis.

Cuarto, si las pruebas y los errores cubren IPv4, IPv6, %zone, hosts vacíos y puertos inválidos.

Quinto, si se utiliza go vet como una señal mientras que la revisión de código y las pruebas de conexión reales verifican la corrección.

Preguntas para aclarar primero

  • ¿Es host una IP simple, un nombre DNS, una autoridad entre corchetes o una mezcla?
  • ¿El puerto es un entero, una cadena o un nombre de servicio? ¿Se permite 0?
  • ¿Deben admitirse direcciones link-local IPv6 y zonas como %eth0?
  • ¿La red es TCP, UDP o un socket Unix?
  • ¿Deberían rechazarse los corchetes y caracteres de control en la entrada del usuario?
  • ¿Puede el CI enlazar un listener de loopback IPv6?

Una respuesta de 30 segundos

“La concatenación simple no puede expresar el límite entre un host IPv6 y su puerto, por lo que 2001:db8::1:443 es ambiguo. Valido el puerto y luego llamo a net.JoinHostPort(host, strconv.Itoa(port)); la biblioteca estándar emite [host]:port para IPv6 y preserva las zonas. No agrego corchetes manualmente. Si se aceptan autoridades completas, las analizo con net.SplitHostPort antes de reconstruirlas. Las pruebas cubren IPv4, IPv6, %zone, DNS, entradas vacías, puertos inválidos y análisis de ida y vuelta. El analizador hostport de go vet en Go 1.25 es una compuerta estática, no un sustituto de las pruebas de red.”

Solución detallada

Paso 1: Explicar el fallo

Una dirección IPv4 tiene un solo signo de dos puntos que separa el host del puerto; una dirección IPv6 contiene dos puntos en sí misma. Por lo tanto, el texto de red IPv6 encierra el host entre corchetes, como en [2001:db8::1]:443. La concatenación simple no proporciona ningún límite, por lo que un analizador no puede determinar de manera confiable si el último signo de dos puntos es el separador de puerto.

Paso 2: Construir con la biblioteca estándar

Convierte el puerto a una cadena y llama a net.JoinHostPort. Cuando el host contiene dos puntos, agrega corchetes; los nombres DNS y IPv4 permanecen en su forma ordinaria. También preserva un identificador de zona, así que no agregues corchetes ni escapes texto antes de llamarlo.

go
func dialAddress(host string, port int) (string, error) {
  if port < 1 || port > 65535 {
    return "", fmt.Errorf("port out of range: %d", port)
  }
  return net.JoinHostPort(host, strconv.Itoa(port)), nil
}

Paso 3: Definir la forma de entrada

La API debe aceptar un host simple, no una autoridad que ya contenga un puerto. Si se deben admitir direcciones completas, primero llama a net.SplitHostPort, normaliza las partes y reconstruye con JoinHostPort. El reemplazo de cadenas no es seguro para IPv6 y zonas.

Paso 4: Manejar identificadores de zona

Una dirección link-local IPv6 puede ser fe80::1%eth0, produciendo [fe80::1%eth0]:443. La zona lleva el alcance de la interfaz y no debe descartarse. Valida sus caracteres permitidos y su longitud para que no entren caracteres de control ni texto de autoridad inesperado en los registros o en la configuración posterior.

Paso 5: Validar y analizar direcciones completas

Después de la construcción, llama a net.SplitHostPort para verificar la reversibilidad y asegurar que el host y el puerto coincidan con las entradas. Requiere una dirección de red que contenga un puerto; los puertos faltantes, dos puntos adicionales y corchetes no coincidentes deben devolver errores procesables.

Paso 6: Comprender go vet hostport

Go 1.25 añade el analizador hostport, que marca los patrones de fmt.Sprintf("%s:%d", host, port) utilizados para construir direcciones para net.Dial. Detecta un error común, pero no puede reemplazar los contratos de configuración, la validación de zonas, los límites de puertos o las pruebas reales de la pila de red.

Paso 7: Construir una matriz de pruebas

Cubre 127.0.0.1:443, [2001:db8::1]:443, [fe80::1%eth0]:443, nombres DNS, un host vacío, puertos 0, 65536, valores negativos y entradas ya entre corchetes. Donde sea compatible, conéctate a listeners de loopback IPv4 e IPv6; de lo contrario, conserva pruebas puras de construcción y división y documenta la capacidad de CI.

Una respuesta de muestra de alta calidad

“El defecto radica en la sintaxis de la dirección, no en Dial: un host IPv6 contiene dos puntos, por lo que la concatenación simple no puede delimitar el puerto. Defino la API como un host simple más un puerto entero, verifico 1..65535 y llamo a net.JoinHostPort(host, strconv.Itoa(port)); nunca escribo corchetes a mano. Si se acepta una autoridad completa, primero la divido y la reconstruyo a partir del host y puerto normalizados. Preservo y valido %eth0 para direcciones link-local. Las pruebas cubren IPv4, IPv6, zonas, DNS, puertos inválidos y análisis reversible. go vet hostport en Go 1.25 es una compuerta estática, mientras que las conexiones de loopback IPv4/IPv6 proporcionan cobertura de integración.”

Errores comunes

  • Seguir usando fmt.Sprintf("%s:%d", ...) Los límites del host y puerto IPv6 son ambiguos → usa net.JoinHostPort.
  • Agregar corchetes a cada host manualmente → Los formatos IPv4 y DNS se vuelven incorrectos → deja que la biblioteca estándar decida.
  • Descartar %zone el tráfico IPv6 link-local podría no enrutarse → preserva y valida la zona.
  • Tratar una autoridad completa como un host simple → los puertos o corchetes se duplican → define el contrato de entrada y divide cuando sea necesario.
  • Probar solo IPv4 → la ruta de fallo en producción permanece sin cubrir → incluye IPv6, zonas y pruebas de loopback.
  • Confiar únicamente en go vet → persisten las entradas personalizadas y los fallos en tiempo de ejecución → combina pruebas unitarias, de división y de conexión.
  • Omitir la validación del puerto → entran valores negativos o con desbordamiento en la configuración → verifica el rango antes de la construcción.
  • Registrar direcciones sin procesar no validadas → pueden filtrarse caracteres de control o configuraciones sensibles → normaliza y registra campos estructurados.

Preguntas de seguimiento

Pregunta de seguimiento 1: ¿Verifica JoinHostPort que host sea una IP válida?

Combina host y puerto de acuerdo con la sintaxis de direcciones de red; no es resolución DNS ni validación completa de negocio. Si se permiten dominios, zonas o caracteres especiales pertenece al contrato de entrada y a la ruta del resolvedor.

Pregunta de seguimiento 2: ¿Por qué no usar simplemente el último signo de dos puntos?

La compresión IPv6, las zonas y los puertos faltantes hacen que las reglas basadas en cadenas sean frágiles. El par estándar Join/Split sigue la sintaxis de direcciones e informa explícitamente errores de corchetes o de puertos.

Pregunta de seguimiento 3: ¿Se puede pasar directamente una cadena de puerto?

Sí, JoinHostPort acepta un puerto como cadena. Cuando la entrada de negocio es un entero, valida su rango y conviértelo con strconv.Itoa para que no se formateen valores negativos o desbordados en una dirección.

Pregunta de seguimiento 4: ¿Cómo se debe sanear una zona?

Preserva la semántica de zona requerida por la interfaz, pero restringe su conjunto de caracteres y longitud. No codifiques doblemente %; registra el host y la zona como campos estructurados separados siempre que sea posible.

Pregunta de seguimiento 5: ¿Cuándo se debe usar url.URL en su lugar?

Usa url.URL cuando construyas URIs HTTP o HTTPS con esquemas, autoridades y rutas. Usa JoinHostPort para el host:port pasado a net.Dial; no concatenes una URI a mano.

Pregunta de seguimiento 6: ¿Cómo demuestras que la corrección funciona con IPv6 real?

En un CI compatible con IPv6 o en un entorno dedicado, enlaza un listener [::1]:0, lee su puerto asignado y conéctate a través del mismo constructor. Mantén pruebas de funciones puras para entornos sin IPv6 y documenta la distinción.

Fuentes públicas

Preguntas relacionadas

Herramienta de entrevista relacionada

Usa Captura para un ejercicio de código

Captura el problema y luego aborda en orden las restricciones, la solución, el código, los casos extremos y la complejidad.

Ver la herramienta