¿Cómo se determinan los puertos de origen y cómo puedo forzarlo a usar un puerto específico?

26

Cuando me conecto a https://www.google.co.uk, esto cambia a 216.58.198.228:443. Luego se abre una conexión conmigo en [Mi dirección IP]: 63998.

Mi pregunta es cómo se elige el puerto 63998 y si hay alguna forma de forzarlo a ser 63999.

TheGathron
fuente
99
¿hay alguna manera de forzarlo a ser 63999? ¿Tienes alguna razón para intentar hacer esto?
AL
1
Si está escribiendo una aplicación, puede abrir cualquier puerto de origen (no utilizado) que desee. Pero no es una buena idea y no está claro por qué quieres esto.
pjc50
66
@ pjc50 De hecho, esta pregunta parece que podría estar teniendo un problema XY .
Dev
1
He enviado una edición para cambiar el título para decir "fuente" en lugar de "local", ya que los números de puerto de destino son "locales" para la máquina de destino, pero la fuente del paquete TCP SYN inicial es inequívocamente la del iniciador de la conexión.
Monty Harder

Respuestas:

39

¿Cómo se determinan los puertos locales?

El software de implementación de TCP elige el número de puerto de un rango de números de puerto llamados Puertos efímeros .

El mecanismo exacto para elegir el número de puerto y el rango a utilizar depende del sistema operativo.


¿Hay alguna manera de obligarlo a ser 63999?

Esto se puede hacer cambiando la configuración del software de implementación TCP.

Las instrucciones sobre cómo configurar el rango de puertos efímeros para una variedad de diferentes sistemas operativos se pueden encontrar en Cambiar el rango de puertos efímeros .

  • Las instrucciones para Linux y Windows se incluyen en esta respuesta a continuación como referencia.

Sin embargo, no es una buena idea restringir el rango a un solo puerto, por ejemplo 63999.

  • De hecho, en Windows esto no es posible ya que:

    El rango mínimo de puertos que se puede configurar es 255.


La efímera gama portuaria

Una conexión TCP / IPv4 consta de dos puntos finales, y cada punto final consta de una dirección IP y un número de puerto. Por lo tanto, cuando un usuario cliente se conecta a una computadora servidor, una conexión establecida puede considerarse como la tupla de 4 (IP del servidor, puerto del servidor, IP del cliente, puerto del cliente).

Por lo general, tres de los cuatro se conocen fácilmente: la máquina del cliente usa su propia dirección IP y cuando se conecta a un servicio remoto, se requiere la dirección IP de la máquina del servidor y el número de puerto de servicio.

Lo que no es inmediatamente evidente es que cuando se establece una conexión, el lado del cliente de la conexión utiliza un número de puerto. A menos que un programa cliente solicite explícitamente un número de puerto específico, el número de puerto utilizado es un número de puerto efímero.

Los puertos efímeros son puertos temporales asignados por la pila de IP de una máquina, y se asignan desde un rango designado de puertos para este propósito. Cuando finaliza la conexión, el puerto efímero está disponible para su reutilización, aunque la mayoría de las pilas de IP no reutilizarán ese número de puerto hasta que se haya utilizado todo el conjunto de puertos efímeros.

Por lo tanto, si el programa cliente se vuelve a conectar, se le asignará un número de puerto efímero diferente para su lado de la nueva conexión.

Fuente El rango de puerto efímero


Cambio de la gama de puertos efímeros

Linux:

Linux le permite ver y cambiar el rango de puerto efímero simplemente usando el archivo /proc/sys/net/ipv4/ip_local_port_range. Por ejemplo, esto muestra la configuración predeterminada en un sistema kernel 2.2:

$ cat /proc/sys/net/ipv4/ip_local_port_range 
1024 4999

Para cambiar esto al rango preferido, puede hacer (como superusuario):

# echo "49152 65535" > /proc/sys/net/ipv4/ip_local_port_range 

Tenga en cuenta que deberá hacer esto cada vez que se inicie el sistema, así que asegúrese de agregar una línea a un script de inicio del sistema /etc/rc.local para que siempre se use su rango.

También tenga en cuenta que el kernel de Linux 2.4 predeterminará el rango de 32768 a 61000 si hay disponible una memoria de kernel adecuada, por lo que puede que no sea necesario cambiar el rango en los sistemas Linux más nuevos.

Finalmente, también tenga en cuenta que puede usar la sysctlinterfaz para cambiar la configuración en lugar de usar el /procsistema de archivos. El nombre del sysctlparámetro es "net.ipv4.ip_local_port_range". Edite el /etc/sysctl.confarchivo si lo tiene, o haga que un script de inicio ejecute el sysctlcomando manualmente si desea cambiar este parámetro usando sysctl.

Windows Vista / Windows Server 2008 y más reciente:

A partir de Windows Vista y Windows Server 2008, Windows ahora usa un amplio rango (49152-65535) de forma predeterminada, de acuerdo con el artículo 929851 de Microsoft Knowledgebase . Ese mismo artículo también muestra cómo puede cambiar el rango si lo desea, pero el rango predeterminado ahora es suficiente para la mayoría de los servidores.

Fuente que cambia el rango de puerto efímero

Puede ver el rango dinámico de puertos en una computadora que ejecuta Windows Vista o Windows Server 2008 usando los siguientes netshcomandos:

netsh int ipv4 show dynamicport tcp
netsh int ipv4 show dynamicport udp
netsh int ipv6 show dynamicport tcp
netsh int ipv6 show dynamicport udp 

Notas:

  • El rango se establece por separado para cada transporte y para cada versión de IP.
  • El rango de puertos ahora es realmente un rango con un punto de partida y un punto final.
  • Los clientes de Microsoft que implementan servidores que ejecutan Windows Server 2008 pueden tener problemas con la comunicación RPC entre servidores si se usan firewalls en la red interna.
  • En estos casos, se recomienda que vuelva a configurar los servidores de seguridad para permitir el tráfico entre los servidores de la gama dinámica de puertos de 49152 por medio 65535.
  • Este rango se suma a los puertos conocidos que utilizan los servicios y las aplicaciones.
  • O bien, el rango de puertos que utilizan los servidores se puede modificar en cada servidor.

Ajusta este rango utilizando el netshcomando, de la siguiente manera:

netsh int <ipv4|ipv6> set dynamic <tcp|udp> start=number num=range

Este comando establece el rango de puerto dinámico para TCP. El puerto de inicio es número y el número total de puertos es rango. Los siguientes son comandos de muestra:

netsh int ipv4 set dynamicport tcp start=10000 num=1000
netsh int ipv4 set dynamicport udp start=10000 num=1000
netsh int ipv6 set dynamicport tcp start=10000 num=1000
netsh int ipv6 set dynamicport udp start=10000 num=1000

Estos comandos de ejemplo configuran el rango de puerto dinámico para comenzar en el puerto 10000 y finalizar en el puerto 10999(1000 puertos).

Notas:

  • El rango mínimo de puertos que se puede configurar es 255.
  • El puerto de inicio mínimo que se puede establecer es 1025.
  • El puerto final máximo (según el rango que se configura) no puede exceder 65535.
  • Para duplicar el comportamiento predeterminado de Windows Server 2003, úselo 1025como puerto de inicio y luego úselo 3976como el rango para TCP y UDP. Esto da como resultado un puerto de inicio 1025y un puerto final de 5000.

Fuente del artículo 929851 de Microsoft Knowledgebase :

Windows XP y versiones anteriores:

Para los sistemas operativos Windows más antiguos (Windows XP y versiones anteriores), Windows utiliza el rango BSD tradicional de 1024 a 4999 para su rango de puertos efímeros. Desafortunadamente, parece que solo puede establecer el límite superior del rango de puertos efímero. Aquí hay información extraída del artículo 196271 de Microsoft Knowledgebase :

  • Inicie el Editor del registro ( Regedt32.exe).
  • Busque la siguiente clave en el registro:

    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

  • En el menú "Editar", haga clic en "Agregar valor" y luego agregue el siguiente valor de registro:

    Nombre del valor: MaxUserPortTipo de datos: REG_DWORDValor: 65534(por ejemplo)

    Rango válido: 5000-65534(decimal) Predeterminado: 0x1388(5000 decimal)

    Descripción: este parámetro controla el número de puerto máximo utilizado cuando una aplicación solicita cualquier puerto de usuario disponible del sistema. Normalmente, los puertos efímeros (es decir, de corta duración) se asignan entre los valores de 1024e 5000inclusive.

  • Salga del Editor del registro.

Nota: Hay otro artículo relevante de KB ( 812873 ) que afirma que le permite establecer un rango de exclusión, lo que podría significar que podría excluir puertos 1024-9999(por ejemplo) para que el rango de puertos sea efímero 10000-65534. Sin embargo, no hemos podido hacer que esto funcione (hasta octubre de 2004).

Fuente que cambia el rango de puerto efímero

DavidPostill
fuente
1
Al menos para Windows parece que es posible restringir el rango de puertos en todo el sistema. En la mayoría de los casos, esta es probablemente una mala idea, especialmente restringirlo a un puerto sería: Ver KB 929851 , los comandos enumerados al menos funcionan en Windows 7.
Septiembre
@Seth Sí. Era reacio a mencionar esto ya que el OP no mencionó su sistema operativo y no quería expandir la respuesta para cubrir los sistemas operativos N ...
DavidPostill
Tienes razón sobre eso. Después de todo, hay muchos sistemas operativos. Es algo con lo que me topé al intentar responder esta pregunta originalmente. Como su respuesta fue más rápida, pensé en agregarla. ¡Es una respuesta muy bien escrita! :) Solo lo agregué como una pista de que a veces cambiar la configuración es suficiente en lugar de reprogramar (tal vez mi comprensión es simplemente diferente, para mí eso suena similar a recompilar).
Seth
1
De hecho, en Linux también es muy simple: simplemente haga eco "49152 65535"> / proc / sys / net / ipv4 / ip_local_port_range . Es tan simple que se puede hacer por comando .
MariusMatutiae
2
En lugar de cambiar el rango de puertos efímero, sería mucho mejor que la aplicación llamara al bindsistema antes de que llame connect. Algunas aplicaciones tienen una opción para hacerlo, otras no.
kasperd
9

La respuesta de David Postill es perfectamente correcta. Solo quisiera agregarle algo más, enfatizando que cambiar el rango de puertos efímeros en Linux es tan simple que el OP tiene una respuesta afirmativa.

Cambia el EPR de la siguiente manera:

echo "40000 60000" > /proc/sys/net/ipv4/ip_local_port_range 

y puede seleccionar el puerto 50000 (como ejemplo) con el siguiente script:

OLD_RANGE=$(cat /proc/sys/net/ipv4/ip_local_port_range)
MY_PORT=50000
echo "$MY_PORT $MY_PORT" > /proc/sys/net/ipv4/ip_local_port_range
sudo -u SomeUser SomeApplication  & 
echo $OLD_RANGE" > /proc/sys/net/ipv4/ip_local_port_range 

Una advertencia aquí: dado que hay un solo puerto en el rango, otra aplicación podría arrebatárselo entre la ejecución de la tercera y la cuarta líneas anteriores; Además, incluso si no hay condición de carrera, paralizará todas las demás aplicaciones hasta que restaure un EPR grande, por lo que restauré el rango original lo antes posible.

Por lo tanto, si el sistema operativo de los OPs hubiera sido Linux, la respuesta habría sido que podría hacerse fácilmente.

Sorprendentemente, esto no es tan sencillo en los BSD, algunos de los cuales ni siquiera tienen una configuración de kernel en tiempo de ejecución para el EPR. MacOS X, FreeBSD y OpenBSD requieren modificar el archivo /etc/sysctl.conf , pero tienen diferentes opciones para el EPR.

Independientemente de lo anterior y del sistema operativo, el hecho de que se pueda hacer algo no significa que deba hacerse: ¿por qué en la Tierra necesitas esto? No puedo pensar en un solo caso de uso.

MariusMatutiae
fuente
Para el ejemplo de Linux +1.
DavidPostill
Jeje. BSD / OS requiere recompilar el núcleo :)
DavidPostill
1
@DavidPostill Eso es un fastidio importante .
MariusMatutiae
Hay una falla en su ejemplo de código. Su tipo de molde está muy fuera de lugar. Además, sería una buena idea hacer BIND_PORTopcional, de modo que el código todavía se pueda usar exactamente de la misma manera que el original. Creo que htons(bind_port_env ? atoi(bind_port_env) : 0)haría lo correcto.
Kasperd
1

Vale la pena agregar que el kernel de Linux también tiene

net.ipv4.ip_local_reserved_ports

perilla que hace algo opuesto pero, sin embargo, podría ser muy útil porque de esa manera puede "perforar un agujero" para servicios que abren puertos específicos en un rango de puertos que de otro modo sería efímero.

Breve extracto de los documentos :

Especifique los puertos que están reservados para aplicaciones de terceros conocidas. Estos puertos no serán utilizados por las asignaciones automáticas de puertos (por ejemplo, al llamar a connect () o bind () con el número de puerto 0). El comportamiento explícito de la asignación de puertos no ha cambiado.

El formato utilizado para entrada y salida es una lista de rangos separados por comas (por ejemplo, "1,2-4,10-10" para los puertos 1, 2, 3, 4 y 10). Escribir en el archivo borrará todos los puertos reservados previamente y actualizará la lista actual con la que figura en la entrada.

poige
fuente