好日子所有,獲取IP地址範圍從xxx.xxx.xx.0/16
有沒有辦法從格式得到一個IP地址範圍66.54.119.192/29
在Oracle pl/sql中類似於66.54.119.192 - 66.54.119.198
感謝您提供任何幫助。
好日子所有,獲取IP地址範圍從xxx.xxx.xx.0/16
有沒有辦法從格式得到一個IP地址範圍66.54.119.192/29
在Oracle pl/sql中類似於66.54.119.192 - 66.54.119.198
感謝您提供任何幫助。
有沒有直接的方式來得到它。首先你需要將IP分成4個八位字節,然後你必須從二進制 - >十進制轉換,反之亦然。
前段時間我爲這樣的任務創建了一個Package。下面你看到的只是包體,它應該提供一切來解決你的問題。
CREATE OR REPLACE TYPE NUMBER_TABLE_TYPE AS TABLE OF NUMBER;
CREATE OR REPLACE PACKAGE BODY IP_Utility AS
BASE_BIN CONSTANT PLS_INTEGER := 2;
BASE_OCT CONSTANT PLS_INTEGER := 8;
BASE_DEC CONSTANT PLS_INTEGER := 10;
BASE_HEX CONSTANT PLS_INTEGER := 16;
NUMERIC_OVERFLOW EXCEPTION;
PRAGMA EXCEPTION_INIT(NUMERIC_OVERFLOW, -1426);
/**
* Function translate a array to PL/SQL Table
* @param Sperator String that separates elements, e.g. ';'
* @return Table of elements (NUMBER)
*/
FUNCTION SplitNumber(LIST IN VARCHAR2, Separator IN VARCHAR2) RETURN NUMBER_TABLE_TYPE IS
OutTable NUMBER_TABLE_TYPE;
BEGIN
IF LIST IS NULL THEN
RETURN NULL;
ELSE
SELECT TRIM(REGEXP_SUBSTR(LIST, '[^'||Separator||']+', 1, LEVEL))
BULK COLLECT INTO OutTable
FROM dual
CONNECT BY REGEXP_SUBSTR(LIST, '[^'||Separator||']+', 1, LEVEL) IS NOT NULL;
END IF;
IF OutTable.COUNT > 0 THEN
RETURN OutTable;
ELSE
RETURN NULL;
END IF;
END SplitNumber;
/**
* 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) := 'ABCDEF';
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) := 'ABCDEF';
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;
/**
* Returns SubnetMask of given IP Address
* @param Ip IP-Address with CIDR, e.g. '10.152.10.17/27'
* @return SubnetMask The Subnet Mask in IPv4 Format, e.g. '255.255.255.224'
*/
FUNCTION GetSubnetMask(Ip IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC IS
SubnetMask VARCHAR2(16);
MaskBin VARCHAR2(32);
BEGIN
IF Ip IS NULL OR NOT REGEXP_LIKE(Ip, '/\d+$') THEN
RETURN NULL;
END IF;
FOR i IN 1..REGEXP_REPLACE(Ip, '.+/') LOOP
MaskBin := MaskBin || '1';
END LOOP;
MaskBin := RPAD(MaskBin, 32, '0');
FOR i IN 1..4 LOOP
SubnetMask := SubnetMask ||'.'||Base2Dec(SUBSTR(MaskBin, 8*(i-1)+1, 8), BASE_BIN);
END LOOP;
SubnetMask := SUBSTR(SubnetMask, 2);
RETURN SubnetMask;
END GetSubnetMask;
/**
* Returns 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
SubnetBin VARCHAR2(8);
BroadcastBin VARCHAR2(8);
Ip_Array NUMBER_TABLE_TYPE;
Mask_Array NUMBER_TABLE_TYPE;
BEGIN
IF SubnetMask IS NULL OR Ip IS NULL THEN
RETURN;
END IF;
Ip_Array := SplitNumber(Ip, '.');
Mask_Array := SplitNumber(SubnetMask, '.');
FOR i IN 1..4 LOOP
SubnetBin := NULL;
BroadcastBin := NULL;
FOR m IN 1..8 LOOP
IF SUBSTR(LPAD(Dec2Base(Ip_Array(i), BASE_BIN), 8, '0'), m, 1) = 1
AND SUBSTR(LPAD(Dec2Base(Mask_Array(i), BASE_BIN), 8, '0'), m, 1) = 1 THEN
SubnetBin := SubnetBin ||'1';
ELSE
SubnetBin := SubnetBin ||'0';
END IF;
IF SUBSTR(LPAD(Dec2Base(Mask_Array(i), BASE_BIN), 8, '0'), m, 1) = 1 THEN
BroadcastBin := SubnetBin;
ELSE
BroadcastBin := BroadcastBin ||'1';
END IF;
END LOOP;
Subnet := Subnet ||'.'||Base2Dec(SubnetBin, BASE_BIN);
BroadcastIp := BroadcastIp ||'.'||Base2Dec(BroadcastBin, BASE_BIN);
END LOOP;
Subnet := SUBSTR(Subnet, 2);
BroadcastIp := SUBSTR(BroadcastIp, 2);
END GetIpSubnet;
END IP_Utility;
/
向我們展示代碼。你有什麼嘗試?應該可以做到。 –
@ MarkJ.Bobak我嘗試使用INET_ATON和INET_NTOA的hacks使用這個SO線程的代碼http://stackoverflow.com/questions/279431/using-sql-to-determine-cidr-value-of-a-subnet-面具。我沒有成功獲得該範圍。 – jasmaar