¿Por qué NAT no reserva los puertos del conjunto de puertos TCP y UDP de la máquina?

8

Hice dos experimentos. Esta es la red para ambos:

        [private network]     [public network]
    A -------------------- R ----------------- B
192.168.0.5     192.168.0.1|192.0.2.1       192.0.2.8

A 's puerta de enlace predeterminada es R . R tiene activo el reenvío de IPv4 y la siguiente regla de iptables:

iptables -t nat -A POSTROUTING -p TCP -j MASQUERADE --to-ports 50000

La intención es que todo TCP de A se enmascarará como 192.0.2.1 usando el puerto 50000 de R.

Publiqué un servicio TCP en el puerto 60000 en B usando nc -4l 192.0.2.8 60000.

Luego abrí una conexión desde A :nc -4 192.0.2.8 60000

A comenzó a enviar paquetes que se veían así:

192.168.0.5:53269 -> 192.0.2.8:60000

R tradujo eso a

192.0.2.1:50000 -> 192.0.2.8:60000

Hasta aquí todo bien.

Luego trató de abrir el siguiente cliente en R : nc -4 192.0.2.8 60000 -p 50000. Envié mensajes, no pasa nada. No se pueden ver paquetes en el tcpdump de R.

Debido a que la regla de enmascaramiento existe, o al menos porque está activa, hubiera esperado que R 'nc fallara con el mensaje de error "nc: Dirección ya en uso", que es lo que sucede si enlazo dos ncs al mismo puerto.

Luego esperé un tiempo para que el mapeo de conntrack muriera.

El segundo experimento consistió en tratar de abrir el cliente de R primero. R comienza a hablar con B muy bien. Si luego abro la conexión desde A , se ignoran sus paquetes. A SYN 's llegan a R , pero no son contestadas, ni siquiera por los errores ICMP. No sé si esto se debe a que R sabe que se quedó sin puertos enmascarados o porque Linux está completamente confundido (técnicamente enmascara el puerto, pero la conexión ya establecida interfiere de alguna manera).

Siento que el comportamiento del NAT es incorrecto. Pude configurar accidentalmente un puerto para enmascarar (particularmente, al no especificar --to-portsdurante la regla de iptables) y un servicio, y el núcleo caerá las conexiones en silencio. Tampoco veo nada de esto documentado en ningún lado.

Por ejemplo:

  • Una hace una petición normal a B . R máscaras usando el puerto 50k.
  • Una hace una consulta DNS para R . Siendo que T es recursivo, R (usando, por pura coincidencia, puerto efímero 50k) consulta el servidor de nombres autorizado Z en el puerto 53.

Acaba de ocurrir una colisión; R ahora está utilizando el puerto 50k para dos conexiones TCP separadas.

Supongo que es porque normalmente no publicas servicios en enrutadores. Pero, de nuevo, ¿dañaría el núcleo "tomar prestado" el puerto del conjunto de puertos TCP cuando se enmascara activamente?

Sé que puedo separar mis puertos efímeros de mi --to-ports. Sin embargo, este no parece ser el comportamiento predeterminado. Tanto NAT como los puertos efímeros tienen por defecto 32768-61000, lo cual es espeluznante.

(Encontré el rango efímero al consultar / proc / sys / net / ipv4 / ip_local_port_range, y el rango NAT simplemente NATizando muchas solicitudes UDP en un experimento separado e imprimiendo el puerto de origen en el lado del servidor. No pude encontrar una forma de imprimir el rango usando iptables.)

Yd Ahhrk
fuente
2
¿Por qué es espeluznante que NAT use el rango de puertos etéreo? Si un cliente en A usa un puerto etéreo que también está en uso en R, obtiene NAT en uno nuevo. ¿Y por qué tener un servicio como DNS o DHCP en R tiene algo que ver con esto? DNS y DHCP no utilizan puertos efímeros (en el lado del servidor). ¿Y por qué usar solo un puerto para enmascarar?
Thomas Erker
@Thomas: Sus preguntas en realidad me llevaron en la dirección correcta, y estoy muy agradecido, pero parece que también tiene una idea errónea: si un cliente en A usa un puerto efímero también en uso en R, no necesariamente conseguir NATed a uno nuevo; NAT no consulta los grupos de puertos TCP / UDP. De hecho, noté que las conexiones NAT en colisión son normales e inofensivas; mira mi respuesta
Yd Ahhrk
@Thomas: No pensé en DHCP a fondo; En realidad estaba pensando en DNS. Me imagino que DNS usa puertos efímeros si es un servidor de nombres recursivo (para consultar los autorizados); mira mi edición
Yd Ahhrk
@Thomas: Todo el experimento tiene la intención de ver qué sucede cuando hay colisiones; Reduje el rango efímero a un solo puerto para forzar la colisión.
Yd Ahhrk

Respuestas:

2

¿Le haría daño al kernel "tomar prestado" el puerto del conjunto de puertos TCP cuando se enmascara activamente?

Supongo que la respuesta es "no, pero no importa mucho".

Asumí incorrectamente que R solo usaba la dirección de transporte de destino del paquete de respuesta para saber si se dirigía hacia A o hacia sí mismo. En realidad, parece usar toda la tupla de direcciones de transporte de origen-destino para identificar una conexión. Por lo tanto, en realidad es normal que NAT cree múltiples conexiones usando el mismo puerto ( propiedad de R ); No crea ninguna confusión. En consecuencia, los grupos de puertos TCP / UDP no importan.

Es bastante obvio ahora que lo pienso.

Luego trató de abrir el siguiente cliente en R : nc -4 192.0.2.8 60000 -p 50000. Envié mensajes, no pasa nada. No se pueden ver paquetes en el tcpdump de R.

Esta es la parte de los experimentos donde me equivoqué.

La falla ocurre porque las direcciones de transporte de origen y destino son las mismas, no solo porque la dirección de origen es la misma.

Si lo hago, por ejemplo, nc -4 192.0.2.8 60001 -p 50000realmente funciona. Incluso si usa el mismo puerto que una máscara NAT.

Siento que el comportamiento del NAT es incorrecto. Pude configurar accidentalmente un puerto para enmascarar (particularmente, al no especificar --to-portsdurante la regla de iptables) y un servicio, y el núcleo caerá las conexiones en silencio.

No lo hará, porque las conexiones enmascaradas y las conexiones iniciadas en R probablemente tendrán diferentes destinos.

Debido a que la regla de enmascaramiento existe, o al menos porque está activa, hubiera esperado que R 'nc fallara con el mensaje de error "nc: Dirección ya en uso", que es lo que sucede si enlazo dos ncs al mismo puerto.

Todavía estoy buscando una respuesta a prueba de balas para esto, pero todo parece apuntar a "es una consecuencia adversa de cómo se implementa, y es tan pequeño que estamos dispuestos a vivir con eso".

Yd Ahhrk
fuente