subred subnetting subneteo formato explicacion cual con como calcular php codeigniter

php - subneteo - subnetting con cidr



Encuentre si existe una IP dada en CIDR o no (2)

Obtengo la dirección IP de un usuario que usa $ _SERVER [''REMOTE_ADDR''] que intenta visitar mi sitio. Tengo diferentes cajas con diferentes IDS y diferentes entradas CIDR en mi base de datos para cada cuadro. Quiero verificar si la IP del usuario existe en alguno de los CIDR o no para un cuadro específico. Si existe, entonces se le permite ingresar, de lo contrario, no. supongamos que el usuario IP es

127.0.0.1

supongamos que las entradas CIDR para el cuadro 12 es

192.168.1.20/27 192.168.0.10/32

Las entradas CIDR se almacenan en una columna en la base de datos

si viene con un IP que se encuentra dentro de este rango, entonces se le debe permitir ingresar al sitio, de lo contrario no. Quiero comprobar su ip contra cada entrada CIDR.

Alguna idea, por favor?

Gracias


Bien, intenta seguir estos 5 sencillos pasos ...

1. Almacene sus CIDR en una matriz (léalos desde la base de datos, supongo que sabes cómo hacerlo)

$cidrs = array( ''192.168.1.20/27'', ''192.168.0.10/32'' );

2. Obtener la IP del usuario (dirección remota)

$user_ip = $_SERVER[''REMOTE_ADDR''];

3. Agregue esta función

function IPvsCIDR($user_ip, $cidr) { $parts = explode(''/'', $cidr); $ipc = explode(''.'', $parts[0]); foreach ($ipc as &$v) $v = str_pad(decbin($v), 8, ''0'', STR_PAD_LEFT); $ipc = substr(join('''', $ipc), 0, $parts[1]); $ipu = explode(''.'', $user_ip); foreach ($ipu as &$v) $v = str_pad(decbin($v), 8, ''0'', STR_PAD_LEFT); $ipu = substr(join('''', $ipu), 0, $parts[1]); return $ipu == $ipc; }

4. Compare la dirección IP del usuario contra $ cidrs

$validaddr = false; foreach ($cidrs as $addr) if (IPvsCIDR($user_ip, $addr)) { $validaddr = true; break; }

5. Decida qué hacer con el usuario

if ($validaddr) { echo "CORRECT IP ADDRESS"; } else { echo "INCORRECT IP ADDRESS"; }

¡Eso es!

cómo funciona esta función Convierte la parte de dirección CIDR (xxxx) en una cadena binaria y toma los primeros N dígitos. Luego realiza el mismo trabajo con la IP del usuario y los controles coinciden con los valores.

Ejemplo 2 (trabajo completo de la función)

function testUserIP($user_ip, $cidrs) { $ipu = explode(''.'', $user_ip); foreach ($ipu as &$v) $v = str_pad(decbin($v), 8, ''0'', STR_PAD_LEFT); $ipu = join('''', $ipu); $res = false; foreach ($cidrs as $cidr) { $parts = explode(''/'', $cidr); $ipc = explode(''.'', $parts[0]); foreach ($ipc as &$v) $v = str_pad(decbin($v), 8, ''0'', STR_PAD_LEFT); $ipc = substr(join('''', $ipc), 0, $parts[1]); $ipux = substr($ipu, 0, $parts[1]); $res = ($ipc === $ipux); if ($res) break; } return $res; }

Uso:

$user_ip = $_SERVER[''REMOTE_ADDR'']; $cidrs = array(''192.168.1.20/27'', ''192.168.0.10/32''); if (testUserIP($user_ip, $cidrs)) { // user ip is ok } else { // access denied }


He estado usando esta función por un tiempo:

<?php /** * Returns TRUE if given IPv4 address belongs to given network, FALSE otherwhise * * @param string $str_ip IP address in ''127.0.0.1'' format * @param string $str_range Network and mask as ''127.0.0.0/8'', ''127.0.0.0/255.0.0.0'' or ''127.0.0.1'' * @return bool * * @version v2011-08-30 */ function ip_belongs_to_network($str_ip, $str_range){ // Extract mask list($str_network, $str_mask) = array_pad(explode(''/'', $str_range), 2, NULL); if( is_null($str_mask) ){ // No mask specified: range is a single IP address $mask = 0xFFFFFFFF; }elseif( (int)$str_mask==$str_mask ){ // Mask is an integer: it''s a bit count $mask = 0xFFFFFFFF << (32 - (int)$str_mask); }else{ // Mask is in x.x.x.x format $mask = ip2long($str_mask); } $ip = ip2long($str_ip); $network = ip2long($str_network); $lower = $network & $mask; $upper = $network | (~$mask & 0xFFFFFFFF); return $ip>=$lower && $ip<=$upper; }

Actualizar:

En realidad, todas las entradas CIDR están en la base de datos en mi caso. ¿Cómo puedo verificar una IP con todas las entradas de CIDR que un bucle foreach puede funcionar?

Depende de cuántas entradas tengas. Un bucle de PHP está bien para un par de rangos, pero tener 50 de ellos implicaría el lanzamiento de 50 consultas SQL. En ese caso, probablemente debería cambiar a un enfoque de base de datos. Por ejemplo, puede almacenar rangos en dos columnas (dirección IP inferior y dirección IP superior). De esa forma, todo lo que necesita hacer sería esto:

$sql = ''SELECT COUNT(1) AS belongs_to_at_least_one_range FROM ranges WHERE :remote_address BETWEEN lower_address AND upper_address LIMIT 1''; $params = array( ''remote_address'' => ip2long($_SERVER[''REMOTE_ADDR'']), );

(O busque todas las coincidencias si lo necesita).

¿Puedes explicar esta línea de list($str_network, $str_mask) = array_pad(explode(''/'', $str_range), 2, NULL); de códigos list($str_network, $str_mask) = array_pad(explode(''/'', $str_range), 2, NULL);

explode(''/'', $str_range) // Split the string at `/` characters array_pad(explode(''/'', $str_range), 2, NULL); // Fill with NULLs if we have less than 2 items list($str_network, $str_mask) = // Store first part in `$str_network` and second part in `$str_mask`