我该如何选择ip范围?

时间:2015-02-05 08:50:50

标签: sql oracle oracle10g

我有src_ip(varchar2)列。我需要像这样选择ip范围:

100.64.0.0/10 - > 100.64.0.0 - 100.127.255.255

我尝试编码到ip地址,但它不适合我。我怎么能这样做?

1 个答案:

答案 0 :(得分:0)

前段时间我创建了一个包含与IP地址相关的功能的包(仅限IPv4)。使用此包,您应该能够编写查询。

CREATE OR REPLACE PACKAGE BODY IP_Utils AS

BASE_BIN CONSTANT INTEGER := 2;
BASE_OCT CONSTANT INTEGER := 8;
BASE_DEC CONSTANT INTEGER := 10;
BASE_HEX CONSTANT INTEGER := 16;


/**
* Convert a decimal nubmer into a binary/octal/hex string 
* @param DecN Integer decimal number
* @param Base The binary base (BASE_BIN, BASE_OCT, BASE_HEX)  
* @return The binary/octal/hex string
*/  
FUNCTION Dec2Base(
        DecN IN INTEGER, 
        Base IN PLS_INTEGER DEFAULT BASE_HEX) 
    RETURN VARCHAR2 DETERMINISTIC IS

    HexString CONSTANT CHAR(16) := '0123456789ABCDEF';
    DecNumber INTEGER := DecN;
    BaseString VARCHAR2(128) := NULL;

BEGIN
    IF DecN IS NULL THEN
        RETURN NULL;
    END IF;
    IF Base > 16 THEN 
        RAISE NUMERIC_OVERFLOW;
    END IF;

    LOOP
        BaseString := SUBSTR(HexString, MOD(DecNumber, Base) + 1, 1 ) || BaseString;
        DecNumber := TRUNC(DecNumber / Base);
        EXIT WHEN DecNumber = 0;
    END LOOP;
    RETURN BaseString;

END Dec2Base;



/**
* Convert a binary/octal/hex number into a decimal value 
* @param BaseString The binary/octal/hex string
* @param Base The binary base (BASE_BIN, BASE_OCT, BASE_HEX)  
* @return The decimal number    
*/
FUNCTION Base2Dec(
        BaseString IN VARCHAR2, 
        Base IN PLS_INTEGER DEFAULT BASE_HEX) 
    RETURN INTEGER DETERMINISTIC IS

    BaseNumber INTEGER := 0;
    HexString CONSTANT CHAR(16) := '0123456789ABCDEF';

BEGIN
    IF Base > 16 THEN 
        RAISE NUMERIC_OVERFLOW;
    END IF;

    IF BaseString IS NULL THEN
        RETURN NULL;
    END IF;
    FOR i IN 1..LENGTH(BaseString) LOOP
        BaseNumber := BaseNumber * Base + INSTR(HexString, UPPER(SUBSTR(BaseString, i, 1))) - 1;
    END LOOP;

    RETURN BaseNumber;
END Base2Dec;



/**
* Convert a IPv4 AP-Address into decimal value 
* @param IP The IP-Address, e. g. '10.151.20.224'  
* @return The decimal equivalent
*/
FUNCTION Ip2Decimal(IP IN VARCHAR2) RETURN INTEGER DETERMINISTIC IS
    DecimalIp NUMBER := 0;
BEGIN

    IF Ip IS NULL THEN 
        RETURN NULL; 
    END IF;

    FOR i IN 1..4 LOOP
        DecimalIp := DecimalIp + REGEXP_SUBSTR(IP, '\d+', 1, i) * 256**(4-i);
    END LOOP;
    RETURN DecimalIp;

END Ip2Decimal;



/**
* Convert an IP-Address from decimal value into IPv4 format 
* @param IpDecimal Decimal IP-Address, 0..4294967295  
* @return The IP in IPv4 format
*/    
FUNCTION Decimal2Ip(IpDecimal IN INTEGER) RETURN VARCHAR2 DETERMINISTIC IS

    IP VARCHAR2(16);
    Octet INTEGER;
    v_IpDecimal INTEGER := IpDecimal;

BEGIN
    IF IpDecimal IS NULL THEN 
        RETURN NULL; 
    END IF;

    IF IpDecimal > 2**32 -1 THEN
        RAISE NUMERIC_OVERFLOW;
    END IF;

    FOR i IN 1..4 LOOP
        Octet := TRUNC(v_IpDecimal/256**(4-i));
        v_IpDecimal := v_IpDecimal - Octet * 256**(4-i);
        IP := IP ||'.'||Octet;
    END LOOP;
    RETURN SUBSTR(IP, 2);

END Decimal2Ip;



/**
* Determines Subnet and Broadcast-Ip of given Ip Address  
* @param Ip IP-Address, e.g. 10.152.10.17
* @param SubnetMask The SubnetMask, e.g. 255.255.255.240  
* @param Subnet Subnet-IP: e.g. 10.152.10.16  
* @param BroadcastIp Broadcast-IP: e.g. 10.152.10.31
*/
PROCEDURE GetIpSubnet(Ip IN VARCHAR2, SubnetMask IN VARCHAR2, Subnet OUT VARCHAR2, BroadcastIp OUT VARCHAR2) IS
    CIDR INTEGER;
    SubnetDec INTEGER;
BEGIN

    IF SubnetMask IS NULL OR Ip IS NULL THEN
        RETURN;
    END IF;

    FOR i IN 1..4 LOOP
        Subnet := Subnet ||'.'||BITAND(REGEXP_SUBSTR(Ip, '\d+', 1, i), REGEXP_SUBSTR(SubnetMask, '\d+', 1, i)); 
    END LOOP;
    Subnet := SUBSTR(Subnet, 2);

    CIDR := SubnetMask2CIDR(SubnetMask);
    SubnetDec := Ip2Decimal(Subnet);
    FOR i IN CIDR..31 LOOP
        SubnetDec := SubnetDec + 2**(31-i); 
    END LOOP;   
    BroadcastIp := Decimal2Ip(SubnetDec);   

END GetIpSubnet;


/**
* Returns SubnetMask of given IP-Address  
* @param Ip IP-Address with CIDR, e.g. 10.152.10.17/27
* @return SubnetMask, e.g. 255.255.255.224
*/
FUNCTION GetSubnetMask(Ip IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC IS
BEGIN
    IF Ip IS NULL OR NOT REGEXP_LIKE(Ip, '/\d{1,2}$') THEN
        RETURN NULL;
    END IF;
    RETURN CIDR2SubnetMask(REGEXP_SUBSTR(Ip, '\d{1,2}$'));  
END GetSubnetMask;



/**
* Returns Subnet of given IP-Address  
* @param Ip IP-Address, e.g. 10.152.10.17
* @param SubnetMask SubnetMask in IPv4 Format, e.g. 255.255.0.0
* @return Subnet in IPv4 Format, e.g. 10.152.0.0
*/
FUNCTION GetSubnetIp(Ip IN VARCHAR2, SubnetMask IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC IS
    Subnet VARCHAR2(16);
    BroadcastIp VARCHAR2(16);
BEGIN
    GetIpSubnet(Ip, SubnetMask, Subnet, BroadcastIp);
    RETURN Subnet;
END GetSubnetIp;



/**
* Returns Broadcast of given IP-Address  
* @param Ip IP-Address, e.g. 10.152.10.17
* @param SubnetMask SubnetMask, e.g. 255.255.0.0
* @return Broadcast in IPv4 Format, e.g. 10.152.255.255
*/
FUNCTION GetBroadcastIp(Ip IN VARCHAR2, SubnetMask IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC IS
    Subnet VARCHAR2(16);
    BroadcastIp VARCHAR2(16);
BEGIN
    GetIpSubnet(Ip, SubnetMask, Subnet, BroadcastIp);
    RETURN BroadcastIp;
END GetBroadcastIp;


/**
* Returns Subnet of given IP-Address  
* @param Ip IP-Address with CIDR, e.g. 10.152.10.17/16
* @return Subnet in IPv4 Format, e.g. 10.152.0.0
*/
FUNCTION GetSubnetIp(Ip IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC IS
    Subnet VARCHAR2(16);
    BroadcastIp VARCHAR2(16);
    SubnetMask VARCHAR2(16);
BEGIN
    SubnetMask := GetSubnetMask(Ip); 
    GetIpSubnet(REGEXP_REPLACE(Ip,'/.+$'), SubnetMask, Subnet, BroadcastIp);
    RETURN Subnet;
END GetSubnetIp;



/**
* Returns Broadcast of given IP-Address   
* @param Ip IP-Address with CIDR, e.g. 10.152.10.17/16
* @return Broadcast in IPv4 Format, e.g. 10.152.255.255
*/    
FUNCTION GetBroadcastIp(Ip IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC IS

    Subnet VARCHAR2(16);
    BroadcastIp VARCHAR2(16);
    SubnetMask VARCHAR2(16);
BEGIN
    SubnetMask := GetSubnetMask(Ip);
    GetIpSubnet(REGEXP_REPLACE(Ip,'/.+$'), SubnetMask, Subnet, BroadcastIp);
    RETURN BroadcastIp;
END GetBroadcastIp;




/**
* Translate SubnetMask to CIDR
* @param SubnetMask SubnetMask in IPv4 Format, e.g. 255.255.255.240
* @return CIDR value, e.g. 26
*/    
FUNCTION SubnetMask2CIDR(SubnetMask VARCHAR2) RETURN INTEGER DETERMINISTIC IS
    IpBin CHAR(32);
BEGIN
    IF SubnetMask IS NULL THEN
        RETURN NULL;
    END IF; 
    IpBin := Dec2Base(Ip2Decimal(SubnetMask), BASE_BIN);
    IF REGEXP_LIKE(IpBin, '^1+0+$') THEN
        RETURN REGEXP_INSTR(IpBin, '0')-1;
    ELSIF REGEXP_LIKE(IpBin, '^1{32}$') THEN
        RETURN 32;
    ELSE
        RAISE VALUE_ERROR;
    END IF;
END SubnetMask2CIDR;



/**
* Translate CIDR to SubnetMask
* @param CIDR Subnet, e.g. 26
* @return SubnetMask in IPv4 Format, e.g  255.255.255.240
*/
FUNCTION CIDR2SubnetMask(CIDR IN INTEGER) RETURN VARCHAR2 DETERMINISTIC IS
BEGIN
    IF CIDR IS NULL THEN
        RETURN NULL;
    END IF;
    IF CIDR NOT BETWEEN 1 AND 32 THEN
        RAISE VALUE_ERROR;
    END IF;

    RETURN Decimal2Ip(Base2Dec(RPAD(LPAD('0', CIDR+1, '1'), 32, '0'), BASE_BIN));
END CIDR2SubnetMask;

END IP_Utils;
/