Cuando disponemos de una infraestructura elaborada para nuestro sitio en Drupal 8/9 o cuando esta se encuentra bajo una infraestructura corporativa, lo mas seguro es que contemos con un Balanceador de carga, CDN o Proxy por el cual pasará toda petición hasta que llegue a nuestra aplicación.
En la siguiente gráfica podrá ver un escenario en donde la petición del usuario debe pasar por un CDN, un Balanceador de carga y finalmente a la red de contenedores de la aplicación.
En este escenario, imagine un módulo que debe tomar la IP del usuario para distinguirlo de otros usuarios, por ejemplo la forma como funciona el módulo de Encuestas para identificar que el usuario ha votado, es decir, necesitamos que la IP original del usuario llegue hasta la aplicación para que pueda funcionar correctamente.
Las distintas capas suelen ir pasando la IP pública a la cabecera HTTP_X_FORWARDED_FOR, sin embargo, en esta pueden venir incluidas IPs de las otras capas como lo puede ver en la siguiente imagen
Drupal ofrece la posibilidad de descartar aquellas IPs que conocemos que hacen parte de nuestra infraestructura y de esta forma asegurarnos de entregar la IP correcta a nuestra aplicación, solo debemos agregar las IPs en un arreglo en la variable $settings en el archivo settings.php como lo puede ver en el siguiente código
$settings['reverse_proxy'] = TRUE;
$settings['reverse_proxy_addresses'] = [10.0.3.173, 10.10.0.20];
Más información en: https://www.drupal.org/node/425990
Sin embargo, ahora imagine que alguno de sus componentes de infraestructura no tiene una IP fija o no es solo uno sino que es parte de una red interna que atiende las peticiones y en muchas ocasiones no será el mismo por tanto la IP varía, esto quiere decir que usted necesitaría definir un rango de IPs, sin embargo la anterior configuración que vimos no acepta Rangos de IPs sino IP's fijas por lo que se convierte en un problema.
Para solucionar ese problema les comparto la siguiente función que he creado para que sea incluida o llamada en el archivo settings.php, la función permite identificar las IPs que hace parte del rango de IPs de Red Interna, si lo son, las agrega a un arreglo que es retornado para que lo podamos usar en nuestra configuración.
function is_privateip(){
$private_ips = [];
// lista de argumentos, puede recibir cuantos argumentos con Ips se le pasen
$arg_list = func_get_args();
foreach($arg_list as $value){
if(is_string($value)){
$value_array = explode(',',$value);
// Se recorre la cadena de IPs convertidas en un arreglo
foreach( $value_array as $ip){
$ip_stripped = str_replace(' ', '', $ip);
// Verifica si la IP es parte del rango interno
if(filter_var(trim($ip_stripped),
FILTER_VALIDATE_IP,
FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
) == false){
// Agrega la IP al arreglo
$private_ips[] = $ip_stripped;
}
}
}
}
return $private_ips;
}
La anterior función permite generar el arreglo de IPs internas y puedo pasarle como parámetro todas las IPs que reciba desde cabeceras siempre y cuando sean una cadena o esa cadena tenga varias IPs separadas por coma, note el siguiente ejemplo.
$private_ips = is_privateip($_SERVER['HTTP_X_REAL_IP'], $_SERVER['HTTP_X_FORWARDED_FOR'], $_SERVER['REMOTE_ADDR']);
Y finalmente la uso
$settings['reverse_proxy'] = TRUE;
$settings['reverse_proxy_addresses'] = $private_ips;
Espero que este pequeño código les sea de utilidad, también estoy seguro que puede ser mejorado mucho mas de acuerdo a sus necesidades y experiencia.