7

In Java, I need to get list of all IP Addresses contained by a given IP network.

For e.g. let the netowork be: 192.168.5.0/24 then the output will be (192.168.5.0 ... 192.168.5.255).

I could think of the following way but it looks dirty, is there any elegant way? There is no function for the same in InetAddress class.

  1. Get Network Ip from the input Ip and subnet mask.

    mask = (long)(0xffffffff) << (32-subnetMask);
    Long netIp = getLongfromIp(Inputip)& mask;
    

The function 'getLongfromIp' contains code from - How to convert string (IP numbers) to Integer in Java

  1. get the number of hosts by Subnet Mask

    maxRange = (long)0x1<<(32-subnetMask);

  2. Get address of all hopes by adding i for i in (0 .. maxRange) in the netIp

  3. Convert the ip from above step to octet string.

Ps: I am sure the the IP Addresses will be in IPV4 only.

Community
  • 1
  • 1
Mangat Rai Modi
  • 5,397
  • 8
  • 45
  • 75
  • 1
    What's the question? – erickson Nov 04 '14 at 20:00
  • I have rephrased by question! My question to get all ip addresses in a specific network for e.g. (192.168.5.0/24) then the output will be (192.168.5.0 ... 192.168.5.255). I have shared the way I am doing but its dirty. I am looking for something more elegant! – Mangat Rai Modi Nov 05 '14 at 06:05
  • Would you include the subnet and broadcast addresses? Or just regular host addresses? What about your solution strikes you as inelegant? – erickson Nov 05 '14 at 06:08
  • Yup, I need them both. I didn't like to convert octet string to long and then vice-versa. I am getting this feeling that same could be done without conversions. – Mangat Rai Modi Nov 05 '14 at 06:16
  • 1
    The `InetAddress` API uses byte arrays. Performing the iteration with a counter in a byte array, rather than an integral type, would be really messy and error-prone, and much slower. Compared to that, conversion with a `ByteBuffer` is fast and succinct. – erickson Nov 05 '14 at 07:04

4 Answers4

12

Answering my own question, solution is to use Apache commons.net library

import org.apache.commons.net.util.*;

SubnetUtils utils = new SubnetUtils("192.168.1.0/24");
String[] allIps = utils.getInfo().getAllAddresses();
//appIps will contain all the ip address in the subnet

Read more: Class SubnetUtils.SubnetInfo

Mangat Rai Modi
  • 5,397
  • 8
  • 45
  • 75
  • 1
    That works. It would be nicer if they implemented an iterator over the addresses instead of trying to stuff them all (could be millions of addresses) in an array. If they implemented `Spliterator`, it would be easy to parallelize operations on the addresses. – erickson Nov 06 '14 at 04:50
  • yup, Its dirty. But given that it supports IPV4, its still manageable. – Mangat Rai Modi Nov 06 '14 at 06:29
  • 1
    But it doesnt get initial and final address – Labeo Oct 14 '15 at 05:38
  • You mean network and broadcast address? There's not really anything useful you can do with those addresses unless you intend on using broadcast messages. – RedShift Jan 02 '20 at 10:28
  • 1
    If you need first and last IP addresses included make sure you set inclusiveHostCount to true. – sedrakpc Aug 23 '21 at 22:54
5

The IPAddress Java library supports both IPv4 and IPv6 subnets in a polymorphic manner. Disclaimer: I am the project manager.

Here is sample code to list the addresses for an IPv4 or Ipv6 subnet transparently. Subnets can get quite large, especially with IPv6, and it is not wise to attempt to iterate through a large subnet, so the code for iterateEdges shows how to iterate through just the beginning and ending addresses in the subnet.

show("192.168.10.0/24");
show("2001:db8:abcd:0012::/64");

static void show(String subnet) throws AddressStringException {
    IPAddressString addrString = new IPAddressString(subnet);
    IPAddress addr = addrString.toAddress();
    show(addr);
}

static void show(IPAddress subnet) {
    Integer prefixLength = subnet.getNetworkPrefixLength();
    if(prefixLength == null) {
        prefixLength = subnet.getBitCount();
    }
    IPAddress mask = subnet.getNetwork().getNetworkMask(prefixLength, false);
    BigInteger count = subnet.getCount();
    System.out.println("Subnet of size " + count + " with prefix length " + prefixLength + " and mask " + mask);
    System.out.println("Subnet ranges from " + subnet.getLower() + " to " + subnet.getUpper());
    int edgeCount = 3;
    if(count.compareTo(BigInteger.valueOf(256)) <= 0) {
        iterateAll(subnet, edgeCount);
    } else {
        iterateEdges(subnet, edgeCount);
    }
}

Iterates through entire subnet, use with caution:

static void iterateAll(IPAddress subnet, int edgeCount) {
    BigInteger count = subnet.getCount();
    BigInteger bigEdge = BigInteger.valueOf(edgeCount), currentCount = count;
    int i = 0;
    for(IPAddress addr: subnet.getIterable()) {
        currentCount = currentCount.subtract(BigInteger.ONE);
        if(i < edgeCount) {
            System.out.println(++i + ": " + addr);
        } else if(currentCount.compareTo(bigEdge) < 0) {
            System.out.println(count.subtract(currentCount) + ": " + addr);
        } else if(i == edgeCount) {
            System.out.println("...skipping...");
            i++;
        }
    }
}

Iterates through subnet edges:

static void iterateEdges(IPAddress subnet, int edgeCount) {
    for(int increment = 0; increment < edgeCount; increment++) {
        System.out.println((increment + 1) + ": " + subnet.getLower().increment(increment));
    }
    System.out.println("...skipping...");
    BigInteger count = subnet.getCount();
    for(int decrement = 1 - edgeCount; decrement <= 0; decrement++) {
        System.out.println(count.add(BigInteger.valueOf(decrement)) + ": " + subnet.getUpper().increment(decrement));
    }
}

Here is the output:

Subnet of size 256 with prefix length 24 and mask 255.255.255.0
Subnet ranges from 192.168.5.0/24 to 192.168.5.255/24
1: 192.168.5.0/24
2: 192.168.5.1/24
3: 192.168.5.2/24
...skipping...
254: 192.168.5.253/24
255: 192.168.5.254/24
256: 192.168.5.255/24

Subnet of size 18446744073709551616 with prefix length 64 and mask ffff:ffff:ffff:ffff::
Subnet ranges from 2001:db8:abcd:12::/64 to 2001:db8:abcd:12:ffff:ffff:ffff:ffff/64
1: 2001:db8:abcd:12::/64
2: 2001:db8:abcd:12::1/64
3: 2001:db8:abcd:12::2/64
...skipping...
18446744073709551614: 2001:db8:abcd:12:ffff:ffff:ffff:fffd/64
18446744073709551615: 2001:db8:abcd:12:ffff:ffff:ffff:fffe/64
18446744073709551616: 2001:db8:abcd:12:ffff:ffff:ffff:ffff/64
Sean F
  • 4,344
  • 16
  • 30
  • 3
    people are to lazy to read your really good answer ... you have to be more short :) – Dirk Hoffmann Jun 27 '19 at 17:04
  • Not sure why but show("10.8.0.1/24"); is not providing the correct answer. It tell me only 1 IP is possible while there are actually 256 variations. show("10.8.0.0/24"); works fine – Macindows Apr 30 '20 at 15:25
  • @Macindows for an address with a non-zero host, change IPAddress addr = addrString.toAddress(); to IPAddress addr = addrString.toAddress().toPrefixBlock(); – Sean F May 04 '20 at 06:32
  • 1
    see here: https://github.com/seancfoley/IPAddress/wiki/Code-Examples#parse-prefixed-as-subnet-or-ip-address – Sean F May 04 '20 at 06:32
  • this is what i needed! tnx! – Macindows May 04 '20 at 07:29
2

To include NetworkAddress and BroadcastAddress

import org.apache.commons.net.util.*;

 SubnetUtils utils = new SubnetUtils("192.168.1.0/28");
       utils.setInclusiveHostCount(true);

       String[] allIps = utils.getInfo().getAllAddresses();
Labeo
  • 5,831
  • 13
  • 47
  • 77
1

The following is the same as Sean's (really nice!) answer using https://seancfoley.github.io/IPAddress/ , it is only reducing the signal to noise ratio:

subnetToIps("192.168.10.0/28");

    public void subnetToIps(String ipOrCidr) {
        IPAddressString addrString = new IPAddressString(ipOrCidr, IPAddressString.DEFAULT_VALIDATION_OPTIONS);
        IPAddress subnet = addrString.toAddress();
        System.out.println("Subnet ranges from " + subnet.getLower() + " to " + subnet.getUpper());

        int i = 0;
        for (IPAddress addr : subnet.getIterable()) {
            System.out.println(++i + ": " + addr);
        }
    }

Dirk Hoffmann
  • 1,444
  • 17
  • 35