How would I get only IPv4 addresses
Asked Answered
P

2

5

I have the following code which is supposed to get only the IPv4 addresses of all active interfaces, but it still returns an IPv6 address on some computers.

public static List<List> getIpAddress() {
    List<String> ip = new ArrayList<>();
    List<List> ipRefined = new ArrayList<>();
    try {
        Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
        while (interfaces.hasMoreElements()) {
            NetworkInterface iface = interfaces.nextElement();
            if (iface.isLoopback() || !iface.isUp())
                continue;
            Enumeration<InetAddress> addresses = iface.getInetAddresses();
            while(addresses.hasMoreElements()) {
                ip.add(addresses.nextElement().getHostAddress());
            }
        }
    } catch (SocketException e) {
        throw new RuntimeException(e);
    }
    for(int x = 0; x < ip.size(); x++){
        if(ip.get(x).contains("%")){
            try {
                if (ip.get(x + 1).contains(".")) {
                    List<String> tempList = new ArrayList<>();
                    tempList.add(ip.get(x).substring(ip.get(x).indexOf("%") + 1));
                    tempList.add(ip.get(x + 1));
                    ipRefined.add(tempList);
                }
            } catch (IndexOutOfBoundsException ae) {
            }
        }
    }
    return ipRefined;
}

I've tried to specify using only IPv4 by using System.setProperty("java.net.preferIPv4Stack" , "true");, but this only causes getIpAddress() to return an empty list. How should I be getting the IPv4 of active interfaces without the use of string manipulation?

EDIT:

Using System.setProperty("java.net.preferIPv4Stack" , "true"); always causes getIpAddress() to return an empty list.

Padnag answered 16/1, 2017 at 18:16 Comment(4)
I'm not sure about this, but as you're reading through the addresses enumeration, what about checking if each address instanceof Inet4Address?Albanese
I could try that, but I think the issue is that the interface is only returning its IPv6. Let me do some debugging real quick.Padnag
It looks like I'm already filtering it so that only IPv4 can be returned when I do if (ip.get(x + 1).contains(".")). I rewrote some of my code to use instanceof instead of using contains(), but it won't change anything. I'm going to update the question with one more detail.Padnag
Only IPv6 addresses contain '%' because IPv4 doesn't have scopeid.Jefferson
D
7

From InterfaceAddress

This class represents a Network Interface address. In short it's an IP address, a subnet mask and a broadcast address when the address is an IPv4 one. An IP address and a network prefix length in the case of IPv6 address.

Here's my code:

Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
  NetworkInterface networkInterface = interfaces.nextElement();
  System.out.println(String.format("networkInterface: %s", networkInterface.toString()));

  if (!networkInterface.isUp()) {
    continue;
  }

  for (InterfaceAddress interfaceAddress : networkInterface.getInterfaceAddresses()) {
    int npf = interfaceAddress.getNetworkPrefixLength();
    InetAddress address = interfaceAddress.getAddress();
    InetAddress broadcast = interfaceAddress.getBroadcast();
    if (broadcast == null && npf != 8) {
      System.out.println(String.format("IPv6: %s; Network Prefix Length: %s", address, npf));
    } else {
      System.out.println(String.format("IPv4: %s; Subnet Mask: %s; Broadcast: %s", address, npf, broadcast));
    }
  }
}
Dunigan answered 16/1, 2017 at 19:41 Comment(1)
A combination of this and substrings solved my question.Padnag
L
1

My Kotlin solution:

  private suspend fun getAllActiveInterfaces(): Sequence<NetworkInterface> {
        return withContext(Dispatchers.IO) {
            NetworkInterface
                .getNetworkInterfaces()
                .asSequence()
                .filter { !it.isLoopback && it.isUp && !blackListedInterfaces.contains(it.name) }
        }
    }
    suspend fun getAllAddresses(): Result<Collection<InetAddress>> {
        return withContextCatching(Dispatchers.IO) {
            getAllActiveInterfaces()
                .map { networkInterface ->
                    networkInterface
                        .also { Timber.d("Interface: ${it.name}") }
                        .interfaceAddresses
                        .mapNotNull { it.address }
                        .filterIsInstance<Inet4Address>()
                }
                .flatten()
                .toSet()
        }
    }
private val blackListedInterfaces = setOf("dummy0")
Looney answered 7/1, 2022 at 19:51 Comment(1)
Nice! The "timber" line threw me for a second. Some comments would be great. Much cleaner that what I had 5 years ago! :PPadnag

© 2022 - 2024 — McMap. All rights reserved.