Question

J'aimerais trouver un moyen de faire une requête SQL qui calculera le cidr (représentation en bits) d'un masque de sous-réseau stocké dans la base de données. Ainsi, par exemple, 255.255.255.0 ou sa valeur décimale (4294967040) est stockée dans la base de données. Je souhaite effectuer une sélection et obtenir une représentation / 24 suivante via la requête.

J'ai effectué les opérations suivantes pour déterminer la dernière adresse IP d'un sous-réseau. J'espère faire quelque chose de similaire pour déterminer la représentation cidr d'un masque.

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

De préférence, il s'agira d'une instruction SQL fonctionnant sous mysql, postgres, oracle, etc.

Était-ce utile?

La solution

Je pense avoir trouvé la solution à mon problème. Voici ce que j'ai fait:

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

En gros, je prends mon masque décimal et le soustrait de la valeur décimale maximale. J'ai ensuite à un log2 sur cette valeur pour obtenir la valeur de logarithme. Puis soustrayez simplement cela de 32 (le bit maximum disponible).

L’espoir qui aide les autres.

Merci

Autres conseils

Les requêtes SQL n'ont pas de construction de boucle procédurale (nonobstant le langage procédural), mais vous pouvez comparer un jeu de lignes à un autre, ce qui est un peu comme une boucle.

Vous n'avez que 32 masques de sous-réseau possibles. Dans ce cas, il est judicieux de créer une petite table contenant ces 32 masques et le numéro CIDR associé.

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));

par exemple. vous devez convertir 255.255.255.252 masque de réseau en masque de bits.

J'utilise toujours cette requête simple (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'));

pas aussi beau qu'on pourrait l'être, mais c'est court et fonctionne comme un charme ..

--
-- 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 */;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top