Domanda

Vorrei trovare un modo per eseguire una query SQL che calcolerà il cidr (rappresentazione bit) di una maschera di sottorete memorizzata nel database. Quindi, ad esempio, ho 255.255.255.0 o il suo valore decimale (4294967040) memorizzato nel database. Vorrei fare una selezione e ottenere indietro / 24 rappresentazione tramite la query.

Ho fatto cose come le seguenti per determinare l'ultimo IP di una sottorete, quindi spero di fare qualcosa di simile per determinare la rappresentazione cidr di una maschera.

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

Preferibilmente questa sarebbe un'istruzione SQL che funzionerebbe sotto mysql, postgres, oracle ecc.

È stato utile?

Soluzione

Penso di aver trovato la soluzione al mio problema. Ecco cosa ho fatto:

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

Praticamente prendo la mia maschera decimale e la sottraggo dal massimo valore decimale. Ho quindi un log2 su quel valore per ottenere il valore del logaritmo. Quindi sottrailo semplicemente da 32 (il bit massimo disponibile).

Spero che aiuti gli altri.

Grazie

Altri suggerimenti

Le query SQL non hanno un costrutto di ciclo procedurale (nonostante il linguaggio procedurale), ma puoi confrontare un insieme di righe con un altro insieme di righe, che è un po 'come un ciclo.

Hai solo 32 possibili subnet mask. In casi come questo, ha senso creare una piccola tabella che memorizza queste 32 maschere e il numero CIDR associato.

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

es. devi convertire 255.255.255.252 maschera di rete in maschera di bit.

Uso sempre questa semplice query (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'));

non è bello come potrebbe essere, ma è corto e funziona come un fascino ..

--
-- 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 */;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top