La dirección IP origen usada cambia al añadir una nueva IP
Hola a todos,
Hace poco hemos estado trabajando en un incidente en el que un equipo Windows Server 2008 R2 SP1 comenzaba a utilizar una dirección IP nueva como origen de sus conexiones. Esta nueva dirección se había configurado como IP adicional.
El equipo tenía una dirección IP principal, configurada en su configuración TCP/IPv4 del tipo A.B.C.50.
El equipo tenía también varias direcciones IP adicionales en la configuración avanzada TCP/IPv4. Estas direcciones iban desde la A.B.C.51 a la A.B.C.63.
A su vez, otro servidor similar tenía la misma configuración, pero con las direcciones: A.B.C.80 (principal) y A.B.C.81-A.B.C.93 (adicionales)
Ambos servidores publicaban diversos sitios web en cada una de esas direcciones IP adicionales. Por delante de ellos, un balanceador de carga enviaba el tráfico a cada IP de dicha pareja. Por ejemplo www.contoso.com era balanceado entre las direcciones A.B.C.51 y la A.B.C.81 (una de cada servidor web).
A su vez, dichos servidores web tenían que conectarse a otros servidores. Estas conexiones salían con la dirección IP origen principal de cada uno de los servidores. En el servidor destino A.B.C.100 se esperaba que las conexiones llegasen con las direcciones IP origen A.B.C.50 y la A.B.C.80.
El problema surgió al añadir una nueva pareja de direcciones IP para publicar un nuevo sitio web. Se optó por mantener la lógica, asignando:
webserver1 – nueva IP A.B.C.64
webserver2 – nueva IP A.B.C.94
Al añadir dicha IP nueva en el webserver1, el servidor comenzaba a utilizar esta IP A.B.C.64 como origen de las conexiones que iniciaba hacia el servidor destino, en lugar de la IP configurada como principal A.B.C.50.
Solución corta
La solución al problema pasa por añadir las direcciones IP por línea de comandos con la herramienta netsh y utilizando la opción SkipAsSource=true. Más información: https://support.microsoft.com/kb/975808
Explicación detallada
El comportamiento que tenemos en este entorno viene derivado del mecanismo de selección de la IP origen. En este artículo se explica muy bien:
Windows XP behavior
(…)
If a source IP is not given the Primary IP address of the adapter with a route that most closely matches the target IP address is used to source the packet and the adapter that the Primary IP is associated with is used as the source adapter.
Windows Vista/Windows Server 2008 behavior
Windows Vista and later are based on the strong host model. In the strong host model, the host can only send packets on an interface if the interface is assigned the source IP address of the packet being sent. Also the concept of a primary IP address does not exist.
Similar to XP when if a program doesn't specify a source IP, the stack references the target IP address, and then examines the entire IP route table so that it can choose the best network adapter over which to send the packet. After the network adapter has been chosen, the stack uses the address selection process defined in RFC 3484 and uses that IP address as the source IP address for the outbound packets.
Y en concreto, esa implementación del RFC 3484 es la siguiente (la parte que nos interesa es la Rule8a):
Windows Source IP V4 address selection:
Rule 1 Prefer same address (applies)
Rule 2 Prefer appropriate scope (applies)
Rule 3 Avoid deprecated addresses (applies)
Rule 4 - Prefer home addresses - does not apply to IP v4
Rule 5 Prefer outgoing Interfaces (applies)
Rule 6 Prefer matching label - does not apply to IP v4
Rule 7 Prefer public addresses - does not apply to IP v4
Rule 8a: Use longest matching prefix with the next hop IP address. (not in RFC!)
If CommonPrefixLen(SA, D) > CommonPrefixLen(SB, D), then prefer SA
Similarly, if CommonPrefixLen(SB, D) > CommonPrefixLen(SA, D), then prefer SB.
This says that the IP with the most high order bits that match the destination of the next hop will be used.
Note: Rule 8 - Use longest matching Prefix is similar to rule 8a except the match is with the destination IP address rather than the next hop IP address.
En este caso particular, el problema no era trivial, ya que justo el rango de direcciones IP definido es lo que estaba provocando este cambio de comportamiento. Haciendo los cálculos en base al algoritmo anterior, tenemos lo siguiente:
Cálculos iniciales
El servidor de destino con el que fallaba el tráfico tenía la IP A.B.C.100
100 decimal = 0110 0100 binario
Selección de la IP origen - los 3 primeros octetos de la IP son siempre los mismos (A.B.C) por lo que solo hacemos los cálculos en binario para el último octeto. Algunos ejemplos:
Caso 1: Primera dirección IP del rango que tiene el servidor:
- A.B.C.50 decimal = 0011 0010 binario
Caso 2: Última IP que al añadirla ha provocado el problema:
- A.B.C.64 decimal = 0100 0000 binario
Caso 3: Última IP con la que se comportaba bien el servidor:
- A.B.C.63 decimal = 0011 1111 binario
Según el algoritmo:
"If CommonPrefixLen(SA, D) > CommonPrefixLen(SB, D), then prefer SA.
Similarly, if CommonPrefixLen(SB, D) > CommonPrefixLen(SA, D), then prefer SB. "
Es decir, para los ejemplos anteriores tenemos:
Caso 1 :
Source A (SA) = A.B.C.50
Source B (SB) = A.B.C.64
CommonPrefixLen(SA, D) = CommonPrefixLen(a.b.c.50, a.b.c.100) -- 25 bits (3 octetos + 1 bit del 4º octeto)
CommonPrefixLen(SB, D) = CommonPrefixLen(a.b.c.64, a.b.c.100) -- 26 bits (3 octetos + 2 bits del 4º octeto)
Resultado: La IP .64 tiene un prefijo común mayor con la dirección IP destino .100, por lo que se usa dicha IP .64 como origen.
Caso 2 :
Source A (SA) = A.B.C.50
Source B (SB) = A.B.C.63
CommonPrefixLen(SA, D) = CommonPrefixLen(a.b.c.50, a.b.c.100) -- 25 bits (3 octetos + 1 bit del 4º octeto)
CommonPrefixLen(SB, D) = CommonPrefixLen(a.b.c.63, a.b.c.100) -- 25 bits (3 octetos + 1 bits del 4º octeto)
Resultado: Las dos direcciones IP tienen el mismo prefijo común, por lo que en este caso, se utiliza la IP menor de ambas (en este caso A.B.C.50). Este resultado es el mismo para todos los casos en los que Source B esté entre A.B.C.51 y A.B.C.63.
El cambio de comportamiento se produce a partir de la IP 64 ya que el bit 7 del último octeto pasa a estar activo (0100 0000), algo que no ocurría en las direcciones inferiores (<=63). Ese bit 7 también está activo en la IP destino D (.100), por lo que el CommonPrefixLen empieza a ser mayor, y se selecciona esa IP como source IP.
Espero que este artículo os haya resultado interesante.
Un saludo,
Sergio Medina Vallejo – Support Escalation Engineer – Microsoft Global Business Support