vlsm subredes subneteo que mascara sql subnet bitmask cidr

subredes - Usar SQL para determinar el valor de cidr de una máscara de subred



subneteo (4)

Las consultas SQL no tienen un constructo de bucle de procedimiento (a pesar del lenguaje de procedimiento), pero puede comparar un conjunto de filas con otro conjunto de filas, que es como un bucle.

Solo tiene 32 posibles máscaras de subred. En casos como este, tiene sentido crear una pequeña tabla que almacene estas 32 máscaras y el número CIDR asociado.

CREATE TABLE cidr ( bits INT UNSIGNED PRIMARY KEY, mask INT UNSIGNED NOT NULL ); INSERT INTO cidr (bits) VALUES ( 1), ( 2), ( 3), ( 4), ( 5), ( 6), ( 7), ( 8), ( 9), (10), (11), (12), (13), (14), (15), (16), (17), (18), (19), (20), (21), (22), (23), (24), (25), (26), (27), (28), (29), (30), (31), (32); UPDATE cidr SET mask = ((POWER(2,32)-1)<<(32-bits)) & (POWER(2,32)-1); SELECT CONCAT(s.ip_addr, ''/'', c.bits) FROM cidr c JOIN subnets s ON (c.mask = inet_aton(s.ip_mask));

Me gustaría encontrar una forma de hacer una consulta SQL que calculará el cidr (representación de bits) de una máscara de subred almacenada en la base de datos. Entonces, por ejemplo, tengo 255.255.255.0 o su valor decimal (4294967040) almacenado en la base de datos. Me gustaría hacer una selección y obtener una representación de 24 a través de la consulta.

He hecho cosas como las siguientes para determinar la última IP de una subred, así que espero hacer algo similar para determinar la representación de cidr de una máscara.

select concat(inet_ntoa(ip_addr),''-'', inet_ntoa(ip_addr+(POWER(2,32)-ip_mask-1))) range from subnets order by ip_addr

Preferiblemente, esta sería una declaración de SQL que funcionaría en mysql, postgres, oráculo, etc.


Creo que encontré la solución a mi problema. Esto es lo que hice:

select CONCAT(INET_NTOA(ip_addr),''/'',32-log2((4294967296-ip_mask))) net from subnets order by ip_addr

Básicamente tomo mi máscara de decimales y la resta del valor decimal máximo. Luego a un log2 en ese valor para obtener el valor del logaritmo. Luego, simplemente resta eso de 32 (el bit máximo disponible).

Espero que ayude a otros.

Gracias


-- -- Dumping routines for database -- /*!50003 DROP FUNCTION IF EXISTS `INET_ATOC` */; /*!50003 SET @saved_cs_client = @@character_set_client */ ; /*!50003 SET @saved_cs_results = @@character_set_results */ ; /*!50003 SET @saved_col_connection = @@collation_connection */ ; /*!50003 SET character_set_client = utf8 */ ; /*!50003 SET character_set_results = utf8 */ ; /*!50003 SET collation_connection = utf8_general_ci */ ; /*!50003 SET @saved_sql_mode = @@sql_mode */ ; /*!50003 SET sql_mode = ''ALLOW_INVALID_DATES'' */ ; DELIMITER ;; CREATE DEFINER=`root`@`localhost` FUNCTION `INET_ATOC`(`paramNETMASK` varchar(15)) RETURNS int(2) unsigned DETERMINISTIC COMMENT ''Converts an IPv4 netmask in dotted decimal notation to a CIDR integer between 0 and 32'' BEGIN DECLARE `netmask` int unsigned; DECLARE `cidr` int unsigned; SET `netmask` = INET_ATON(`paramNETMASK`); IF (`netmask` IS NULL) THEN RETURN NULL; ELSE SET `cidr` = 0; countNetBits: WHILE (`cidr` < 32) DO IF ( (0x80000000 & `netmask`) = 0x80000000 ) THEN SET `netmask` = 0xFFFFFFFF & (`netmask` << 1); SET `cidr` = `cidr` + 1; ELSE LEAVE countNetBits; END IF; END WHILE; IF (`netmask` != 0) THEN RETURN NULL; END IF; RETURN `cidr`; END IF; END ;; DELIMITER ; /*!50003 SET sql_mode = @saved_sql_mode */ ; /*!50003 SET character_set_client = @saved_cs_client */ ; /*!50003 SET character_set_results = @saved_cs_results */ ; /*!50003 SET collation_connection = @saved_col_connection */ ; /*!50003 DROP FUNCTION IF EXISTS `INET_CTOA` */; /*!50003 SET @saved_cs_client = @@character_set_client */ ; /*!50003 SET @saved_cs_results = @@character_set_results */ ; /*!50003 SET @saved_col_connection = @@collation_connection */ ; /*!50003 SET character_set_client = utf8 */ ; /*!50003 SET character_set_results = utf8 */ ; /*!50003 SET collation_connection = utf8_general_ci */ ; /*!50003 SET @saved_sql_mode = @@sql_mode */ ; /*!50003 SET sql_mode = ''ALLOW_INVALID_DATES'' */ ; DELIMITER ;; CREATE DEFINER=`root`@`localhost` FUNCTION `INET_CTOA`(`paramCIDR` int) RETURNS varchar(15) CHARSET utf8 DETERMINISTIC COMMENT ''Converts a CIDR suffix (integer between 0 and 32) to an IPv4 netmask in dotted decimal notation'' BEGIN DECLARE `netmask` int unsigned; IF ( (`paramCIDR` < 0) OR (`paramCIDR` > 32) ) THEN RETURN NULL; ELSE SET `netmask` = 0xFFFFFFFF - (pow( 2, (32-`paramCIDR`) ) - 1); RETURN INET_NTOA(`netmask`); END IF; END ;; DELIMITER ; /*!50003 SET sql_mode = @saved_sql_mode */ ; /*!50003 SET character_set_client = @saved_cs_client */ ; /*!50003 SET character_set_results = @saved_cs_results */ ; /*!50003 SET collation_connection = @saved_col_connection */ ; /*!50003 DROP PROCEDURE IF EXISTS `getSubnet` */; /*!50003 SET @saved_cs_client = @@character_set_client */ ; /*!50003 SET @saved_cs_results = @@character_set_results */ ; /*!50003 SET @saved_col_connection = @@collation_connection */ ; /*!50003 SET character_set_client = utf8 */ ; /*!50003 SET character_set_results = utf8 */ ; /*!50003 SET collation_connection = utf8_general_ci */ ; /*!50003 SET @saved_sql_mode = @@sql_mode */ ; /*!50003 SET sql_mode = '''' */ ; DELIMITER ;; CREATE DEFINER=`root`@`localhost` PROCEDURE `getSubnet`(INOUT `paramADDR` VARCHAR(15), INOUT `paramCIDR` INT, OUT `paramMASK` VARCHAR(15), OUT `paramNETWORK` VARCHAR(15), OUT `paramBROADCAST` VARCHAR(15), OUT `paramNUMHOSTS` INT) CHARSET utf8 DETERMINISTIC BEGIN DECLARE `numaddrs` int unsigned; DECLARE `ipaddr` int unsigned; DECLARE `netmask` int unsigned; DECLARE `wildcard` int unsigned; DECLARE `network` int unsigned; DECLARE `broadcast` int unsigned; DECLARE `numhosts` int unsigned; SET `ipaddr` = INET_ATON(`paramADDR`); IF (`ipaddr` IS NULL) OR (`paramCIDR` < 1) OR (`paramCIDR` > 30) THEN SELECT NULL, NULL, NULL, NULL, NULL, NULL INTO `paramADDR`, `paramCIDR`, `paramMASK`, `paramNETWORK`, `paramBROADCAST`, `paramNUMHOSTS`; ELSE SET `numaddrs` = pow( 2, (32-`paramCIDR`) ); SET `numhosts` = `numaddrs` - 2; SET `netmask` = 0xFFFFFFFF - (`numaddrs` - 1); SET `wildcard` = 0xFFFFFFFF & (~`netmask`); SET `network` = `ipaddr` & `netmask`; SET `broadcast` = `ipaddr` | `wildcard`; SELECT INET_NTOA(`ipaddr`), `paramCIDR`, INET_NTOA(`netmask`), INET_NTOA(`network`), INET_NTOA(`broadcast`), `numhosts` INTO `paramADDR`, `paramCIDR`, `paramMASK`, `paramNETWORK`, `paramBROADCAST`, `paramNUMHOSTS`; END IF; END ;; DELIMITER ; /*!50003 SET sql_mode = @saved_sql_mode */ ; /*!50003 SET character_set_client = @saved_cs_client */ ; /*!50003 SET character_set_results = @saved_cs_results */ ; /*!50003 SET collation_connection = @saved_col_connection */ ; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;


por ejemplo, necesitas convertir 255.255.255.252 máscara de red en máscara de bits.

Yo siempre uso esta simple consulta (PostgreSQL):

SELECT 32-length(trim(((split_part(''255.255.255.252'',''.'',1)::bigint*(256^3)::bigint + split_part(''255.255.255.252'',''.'',2)::bigint*(256^2)::bigint + split_part(''255.255.255.252'',''.'',3)::bigint*256 + split_part(''255.255.255.252'',''.'',4)::bigint)::bit(32))::text,''1''));

no tan lindo como podría ser, pero es corto y funciona como un encanto ...