ex.IPv6地址與CIDR: 2620:0:2d0:200 :: 7/32 輸出 開始範圍:2620:0:0:0: 0:0:0:0 結束範圍:2620:0:ffff:ffff:ffff:ffff:ffff:fffforacle PL/SQL如何計算IPv6的範圍ip cidr
如何使用PL/SQL進行計算?
ex.IPv6地址與CIDR: 2620:0:2d0:200 :: 7/32 輸出 開始範圍:2620:0:0:0: 0:0:0:0 結束範圍:2620:0:ffff:ffff:ffff:ffff:ffff:fffforacle PL/SQL如何計算IPv6的範圍ip cidr
如何使用PL/SQL進行計算?
有一次,我寫了一個一般的PL/SQL程序包,你可以做這樣的轉換:
CREATE OR REPLACE PACKAGE BODY Misc_Util AS
NUMERIC_OVERFLOW EXCEPTION;
PRAGMA EXCEPTION_INIT(NUMERIC_OVERFLOW, -1426);
BASE_BIN CONSTANT PLS_INTEGER := 2;
BASE_OCT CONSTANT PLS_INTEGER := 8;
BASE_HEX CONSTANT PLS_INTEGER := 16;
FUNCTION Dec2Base(DecN IN NUMBER, Base IN PLS_INTEGER DEFAULT BASE_HEX) RETURN VARCHAR2 DETERMINISTIC IS
HexString VARCHAR2(33);
n INTEGER;
BaseString VARCHAR2(129) := NULL;
DecNumber NUMBER := DecN;
BEGIN
IF DecN IS NULL THEN
RETURN NULL;
ELSIF Base NOT IN (BASE_BIN, BASE_OCT, BASE_HEX) THEN
RAISE INVALID_NUMBER;
ELSIF DecN > 2**128 - 1 THEN
RAISE NUMERIC_OVERFLOW;
ELSIF base = BASE_HEX THEN
RETURN TO_CHAR(DecN, 'fmXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
ELSE
IF Base = BASE_BIN THEN
-- Since "MOD(DecNumber, Base)" returns wrong result for numbers > 2^127 I have to make it differently.
HexString := TO_CHAR(DecN, 'fmXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
FOR i IN 1..LENGTH(HexString) LOOP
n := TO_NUMBER(SUBSTR(HexString, -i, 1), 'X');
BaseString := SIGN(BITAND(n, 8)) || SIGN(BITAND(n, 4)) || SIGN(BITAND(n, 2)) || SIGN(BITAND(n, 1)) || BaseString;
END LOOP;
RETURN COALESCE(REGEXP_REPLACE(BaseString, '^0+'), 0);
ELSE
HexString := '';
LOOP
BaseString := SUBSTR(HexString, MOD(DecNumber, Base) + 1, 1) || BaseString;
DecNumber := TRUNC(DecNumber/Base);
EXIT WHEN DecNumber = 0;
END LOOP;
RETURN BaseString;
END IF;
END IF;
END Dec2Base;
FUNCTION Base2Dec(BaseString IN VARCHAR2, Base IN PLS_INTEGER DEFAULT BASE_HEX) RETURN NUMBER DETERMINISTIC IS
BaseNumber NUMBER := 0;
HexString CONSTANT CHAR(16) := 'ABCDEF';
BEGIN
IF BaseString IS NULL THEN
RETURN NULL;
ELSIF Base NOT IN (BASE_BIN, BASE_OCT, BASE_HEX) THEN
RAISE INVALID_NUMBER;
ELSIF Base = BASE_HEX THEN
RETURN TO_NUMBER(BaseString, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
ELSE
FOR i IN 1..LENGTH(BaseString) LOOP
BaseNumber := BaseNumber * Base + INSTR(HexString, UPPER(SUBSTR(BaseString, i, 1))) - 1;
END LOOP;
RETURN BaseNumber;
END IF;
END Base2Dec;
FUNCTION UncompressIpV6(Ip IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC IS
IpFull VARCHAR2(40);
BEGIN
IF REGEXP_LIKE(Ip, '::') THEN
IpFull := Ip;
FOR i IN LENGTH(REGEXP_REPLACE(REGEXP_REPLACE(Ip, '/\d{1,3}$'), '[[:xdigit:]]+', NULL))..7 LOOP
IpFull := REGEXP_REPLACE(IpFull, '::', ':0::');
END LOOP;
RETURN REGEXP_REPLACE(IpFull, '::', ':');
ELSE
RETURN Ip;
END IF;
END UncompressIpV6;
FUNCTION Ip2Decimal(IP IN VARCHAR2) RETURN NUMBER DETERMINISTIC IS
DecimalIp NUMBER := 0;
BEGIN
IF REGEXP_LIKE(IP, ':') THEN
SELECT SUM(Base2Dec(REGEXP_SUBSTR(UncompressIpV6(IP), '[[:xdigit:]]+', 1, LEVEL), BASE_HEX) * POWER(65536, 8-LEVEL))
INTO DecimalIp
FROM dual
CONNECT BY LEVEL <= 8;
RETURN DecimalIp;
ELSE
SELECT SUM(REGEXP_SUBSTR(IP, '\d+', 1, LEVEL) * POWER(256, 4-LEVEL))
INTO DecimalIp
FROM dual
CONNECT BY LEVEL <= 4;
RETURN DecimalIp;
END IF;
END Ip2Decimal;
FUNCTION Decimal2Ip(IpDecimal IN NUMBER) 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;
FUNCTION Decimal2IPv6(IpDecimal IN NUMBER) RETURN VARCHAR2 DETERMINISTIC IS
IP VARCHAR2(40);
Octet INTEGER;
v_IpDecimal NUMBER := IpDecimal;
BEGIN
IF IpDecimal IS NULL THEN
RETURN NULL;
END IF;
IF IpDecimal > 2**128 - 1 THEN
RAISE NUMERIC_OVERFLOW;
END IF;
FOR i IN 1..8 LOOP
Octet := TRUNC(v_IpDecimal/65536**(8-i));
v_IpDecimal := v_IpDecimal - Octet * 65536**(8-i);
IP := IP ||':'||Dec2Base(Octet, BASE_HEX);
END LOOP;
RETURN LOWER(SUBSTR(IP, 2));
END Decimal2IPv6;
FUNCTION GetSubnetMask(Ip IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC IS
BEGIN
IF Ip IS NULL OR NOT REGEXP_LIKE(Ip, '/\d{1,3}$') THEN
RETURN NULL;
END IF;
IF REGEXP_LIKE(Ip, ':') THEN
RETURN CIDR2SubnetMaskV6(REGEXP_SUBSTR(Ip, '\d{1,3}$'));
ELSE
RETURN CIDR2SubnetMask(REGEXP_SUBSTR(Ip, '\d{1,2}$'));
END IF;
END GetSubnetMask;
FUNCTION GetSubnetIp(Ip IN VARCHAR2, SubnetMask IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC IS
Subnet VARCHAR2(40);
BroadcastIp VARCHAR2(40);
BEGIN
GetIpSubnet(Ip, SubnetMask, Subnet, BroadcastIp);
RETURN Subnet;
END GetSubnetIp;
FUNCTION GetBroadcastIp(Ip IN VARCHAR2, SubnetMask IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC IS
Subnet VARCHAR2(40);
BroadcastIp VARCHAR2(40);
BEGIN
GetIpSubnet(Ip, SubnetMask, Subnet, BroadcastIp);
RETURN BroadcastIp;
END GetBroadcastIp;
FUNCTION GetSubnetIp(Ip IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC IS
Subnet VARCHAR2(40);
BroadcastIp VARCHAR2(40);
SubnetMask VARCHAR2(40);
BEGIN
SubnetMask := GetSubnetMask(Ip);
GetIpSubnet(REGEXP_REPLACE(Ip,'/\d{1,3}$'), SubnetMask, Subnet, BroadcastIp);
RETURN Subnet;
END GetSubnetIp;
FUNCTION GetBroadcastIp(Ip IN VARCHAR2) RETURN VARCHAR2 DETERMINISTIC IS
Subnet VARCHAR2(40);
BroadcastIp VARCHAR2(40);
SubnetMask VARCHAR2(40);
BEGIN
SubnetMask := GetSubnetMask(Ip);
GetIpSubnet(REGEXP_REPLACE(Ip,'/\d{1,3}$'), SubnetMask, Subnet, BroadcastIp);
RETURN BroadcastIp;
END GetBroadcastIp;
PROCEDURE GetIpSubnet(Ip IN VARCHAR2, SubnetMask IN VARCHAR2, Subnet OUT VARCHAR2, BroadcastIp OUT VARCHAR2) IS
CIDR INTEGER;
SubnetDec NUMBER;
BEGIN
IF SubnetMask IS NULL OR Ip IS NULL THEN
RETURN;
END IF;
IF REGEXP_LIKE(Ip, ':') THEN
FOR i IN 1..8 LOOP
Subnet := Subnet ||':'||Dec2Base(BITAND(Base2Dec(REGEXP_SUBSTR(UncompressIpV6(Ip), '[[:xdigit:]]+', 1, i), BASE_HEX), Base2Dec(REGEXP_SUBSTR(SubnetMask, '[[:xdigit:]]+', 1, i), BASE_HEX)), BASE_HEX);
END LOOP;
Subnet := SUBSTR(Subnet, 2);
ELSE
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);
END IF;
CIDR := SubnetMask2CIDR(SubnetMask);
SubnetDec := Ip2Decimal(Subnet);
IF REGEXP_LIKE(Ip, ':') THEN
FOR i IN CIDR..127 LOOP
SubnetDec := SubnetDec + 2**(127-i);
END LOOP;
BroadcastIp := Decimal2IpV6(SubnetDec);
ELSE
FOR i IN CIDR..31 LOOP
SubnetDec := SubnetDec + 2**(31-i);
END LOOP;
BroadcastIp := Decimal2Ip(SubnetDec);
END IF;
END GetIpSubnet;
FUNCTION SubnetMask2CIDR(SubnetMask VARCHAR2) RETURN INTEGER DETERMINISTIC IS
IpBin VARCHAR(129);
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}$') AND REGEXP_LIKE(SubnetMask, '\.') THEN
RETURN 32;
ELSIF REGEXP_LIKE(IpBin, '^1{128}$') AND REGEXP_LIKE(SubnetMask, ':') THEN
RETURN 128;
ELSE
RAISE VALUE_ERROR;
END IF;
END SubnetMask2CIDR;
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;
FUNCTION CIDR2SubnetMaskV6(CIDR IN INTEGER) RETURN VARCHAR2 DETERMINISTIC IS
BEGIN
IF CIDR IS NULL THEN
RETURN NULL;
END IF;
IF CIDR NOT BETWEEN 1 AND 128 THEN
RAISE VALUE_ERROR;
END IF;
RETURN Decimal2IpV6(Base2Dec(RPAD(LPAD('0', CIDR+1, '1'), 128, '0'), BASE_BIN));
END CIDR2SubnetMaskV6;
Misc_Util;
/
然後你可以使用它,例如像這樣:
SELECT
Misc_Util.GetSubnetIp('2620:0:2d0:200::7/32'),
Misc_Util.GetBroadcastIp('2620:0:2d0:200::7/32')
FROM dual;
2620:0:0:0:0:0:0:0 2620:0:ffff:ffff:ffff:ffff:ffff:ffff
非常感謝你,我會試試看。 –
It works。謝謝你 –
然後請接受答案 –
這對於IPv4工作HTTP:/ /stackoverflow.com/questions/20959302/get-ip-address-range-from-xxx-xxx-xx-0-16但我想找到範圍IPv6 –
是的,這是我的軟件包的舊版本。下面你看到的版本也支持IPv6 –