seancfoley / IPAddress

Java library for handling IP addresses and subnets, both IPv4 and IPv6
https://seancfoley.github.io/IPAddress/
Apache License 2.0
469 stars 63 forks source link

Extrapolating partial IP string into a Set of IPAddressSeqRange #88

Closed maytasm closed 2 years ago

maytasm commented 2 years ago

Is there any feature to support extrapolating partial IP string into a Set of IPAddressSeqRange? For example,

seancfoley commented 2 years ago

Yes, I think a combination of code and using the right wildcards can do this.

The result does not need to be a set of IPAddressSeqRange, they can all be represented as IPAddress instances.

        test("192.168.");
        test("192.1");
        test("2");
        test("3");
        test("3.");
        test("3.3");
        test("2:");
        test("2::");
        test("2::2");
        test("2:2");
        test("::");
        test("::2");
        test("1:2:3:4:5::7");
        test("1.2.3.4");
        test("1.2.3.");
        test("1.2.3");

    static void test(String str) throws AddressStringException {
        System.out.print("Original string is: ");
        System.out.println(str);
        IPAddress result[] = extrapolate(str);
        System.out.print("Subnets are: ");
        print(result);
        System.out.println();
    }

    static IPAddress[] extrapolate(String str) throws AddressStringException {
        String strs[] = extrapolateStrings(str);
        System.out.print("Address strings are: ");
        print(strs);
        IPAddress addresses[] = new IPAddress[strs.length];
        int i = 0;
        for(String addrStr : strs) {
            addresses[i++] = new IPAddressString(addrStr).getAddress();
        }
        return addresses;
    }

    static String[] extrapolateStrings(String str) throws AddressStringException {
        int ipv6Index = str.lastIndexOf(IPv6Address.SEGMENT_SEPARATOR);
        String strs[];
        if(ipv6Index == -1) {
            int ipv4Index = str.lastIndexOf(IPv4Address.SEGMENT_SEPARATOR);
            if(ipv4Index == -1) {
                for(int i = 0; i < str.length(); i++) {
                    char c = str.charAt(i);
                    if((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
                        return extrapolate(str, -1, 1, false);
                    }
                }
                String ipv4Strs[] = extrapolate(str, -1, 1, true);
                String ipv6Strs[] = extrapolate(str, -1, 1, false);
                strs = new String[ipv4Strs.length + ipv6Strs.length];
                System.arraycopy(ipv4Strs, 0, strs, 0, ipv4Strs.length);
                System.arraycopy(ipv6Strs, 0, strs, ipv4Strs.length, ipv6Strs.length);
            } else {
                int segCount = 2;
                for(int i = ipv4Index; i >= 0; segCount++) {
                    i = str.substring(0, i).lastIndexOf(IPv4Address.SEGMENT_SEPARATOR);
                    if(i == -1) {
                        break;
                    }
                }
                strs = extrapolate(str, ipv4Index, segCount, true);
            }
        } else {
            if(ipv6Index == 0) {
                throw new AddressStringException(str);
            }
            int segCount = 2;
            for(int i = ipv6Index; i >= 0; segCount++) {
                i = str.substring(0, i).lastIndexOf(IPv6Address.SEGMENT_SEPARATOR);
                if(i == -1) {
                    break;
                }
            }
            strs = extrapolate(str, ipv6Index, segCount, false);
        }
        return strs;
    }

    static String singleDigitWildcards = "" + IPAddress.SEGMENT_SQL_SINGLE_WILDCARD + 
            IPAddress.SEGMENT_SQL_SINGLE_WILDCARD +
            IPAddress.SEGMENT_SQL_SINGLE_WILDCARD;

    static String[]  extrapolate(String str, int lastSeparatorIndex, int totalSegs, boolean isIPv4) {
        int maxSegSize = isIPv4 ? 3 : 4;
        int maxSegCount = isIPv4 ? IPv4Address.SEGMENT_COUNT : IPv6Address.SEGMENT_COUNT;
        char sep = isIPv4 ? IPv4Address.SEGMENT_SEPARATOR : IPv6Address.SEGMENT_SEPARATOR;
        int lastSegSize = str.length() - lastSeparatorIndex - 1;
        if(lastSegSize == 0) {
            return new String[] {str + IPAddress.SEGMENT_WILDCARD};
        }
        ArrayList<String> strs = new ArrayList<String>(4);
        char firstChar = str.charAt(lastSeparatorIndex + 1);
        String moreSegs = "" + sep + IPAddress.SEGMENT_WILDCARD;
        for(int segCharCount = lastSegSize; segCharCount <= maxSegSize; segCharCount++) {
            if(isIPv4 && segCharCount == maxSegSize && firstChar != '1' && firstChar != '2' && firstChar != '0'){
                    break;
            }
            String segEnd = singleDigitWildcards.substring(0, segCharCount - lastSegSize);
            String addr;
            if(totalSegs < maxSegCount) {
                addr = str + segEnd + moreSegs;
            } else {
                addr = str + segEnd;
            }
            strs.add(addr);
        }
        return strs.toArray(new String[strs.size()]);
    }

    static void print(Object addresses[]) {
        System.out.println(Arrays.asList(addresses));
    }

Output:

Original string is: 192.168.
Address strings are: [192.168.*]
Subnets are: [192.168.*.*]

Original string is: 192.1
Address strings are: [192.1.*, 192.1_.*, 192.1__.*]
Subnets are: [192.1.*.*, 192.10-19.*.*, 192.100-199.*.*]

Original string is: 2
Address strings are: [2.*, 2_.*, 2__.*, 2:*, 2_:*, 2__:*, 2___:*]
Subnets are: [2.*.*.*, 20-29.*.*.*, 200-255.*.*.*, 2:*:*:*:*:*:*:*, 20-2f:*:*:*:*:*:*:*, 200-2ff:*:*:*:*:*:*:*, 2000-2fff:*:*:*:*:*:*:*]

Original string is: 3
Address strings are: [3.*, 3_.*, 3:*, 3_:*, 3__:*, 3___:*]
Subnets are: [3.*.*.*, 30-39.*.*.*, 3:*:*:*:*:*:*:*, 30-3f:*:*:*:*:*:*:*, 300-3ff:*:*:*:*:*:*:*, 3000-3fff:*:*:*:*:*:*:*]

Original string is: 3.
Address strings are: [3.*]
Subnets are: [3.*.*.*]

Original string is: 3.3
Address strings are: [3.3.*, 3.3_.*]
Subnets are: [3.3.*.*, 3.30-39.*.*]

Original string is: 2:
Address strings are: [2:*]
Subnets are: [2:*:*:*:*:*:*:*]

Original string is: 2::
Address strings are: [2::*]
Subnets are: [2::*]

Original string is: 2::2
Address strings are: [2::2:*, 2::2_:*, 2::2__:*, 2::2___:*]
Subnets are: [2::2:*, 2::20-2f:*, 2::200-2ff:*, 2::2000-2fff:*]

Original string is: 2:2
Address strings are: [2:2:*, 2:2_:*, 2:2__:*, 2:2___:*]
Subnets are: [2:2:*:*:*:*:*:*, 2:20-2f:*:*:*:*:*:*, 2:200-2ff:*:*:*:*:*:*, 2:2000-2fff:*:*:*:*:*:*]

Original string is: ::
Address strings are: [::*]
Subnets are: [::*]

Original string is: ::2
Address strings are: [::2:*, ::2_:*, ::2__:*, ::2___:*]
Subnets are: [::2:*, ::20-2f:*, ::200-2ff:*, ::2000-2fff:*]

Original string is: 1:2:3:4:5::7
Address strings are: [1:2:3:4:5::7:*, 1:2:3:4:5::7_:*, 1:2:3:4:5::7__:*, 1:2:3:4:5::7___:*]
Subnets are: [1:2:3:4:5:0:7:*, 1:2:3:4:5:0:70-7f:*, 1:2:3:4:5:0:700-7ff:*, 1:2:3:4:5:0:7000-7fff:*]

Original string is: 1.2.3.4
Address strings are: [1.2.3.4, 1.2.3.4_]
Subnets are: [1.2.3.4, 1.2.3.40-49]

Original string is: 1.2.3.
Address strings are: [1.2.3.*]
Subnets are: [1.2.3.*]

Original string is: 1.2.3
Address strings are: [1.2.3.*, 1.2.3_.*]
Subnets are: [1.2.3.*, 1.2.30-39.*]