NetworkInterface.getNetworkInterfaces() not listing all interfaces
Asked Answered
D

3

19

I have three interfaces (eth0,Loopback,wlan0) on my machine and i want to get use Java-API to get the mac address.

  • I use this code.

    Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
        for (NetworkInterface netint : Collections.list(nets))
            displayInterfaceInformation(netint);
    }
    
    static void displayInterfaceInformation(NetworkInterface netint) 
      throws SocketException 
    {
        System.out.println("Display name: " 
           + netint.getDisplayName());
        System.out.println("Hardware address: " 
           + Arrays.toString(netint.getHardwareAddress()));
    }
    
  • But that code print wlan0,loopback, but missed eth0 .

  • My OS Ubuntu, any help.

Update

  • The o/p (strace -f java Networks 2>&1| grep ioctl).. blank(empty).

  • java -version

java version "1.7.0_21" Java(TM) SE Runtime Environment (build 1.7.0_21-b11) Java HotSpot(TM) 64-Bit Server VM (build 23.21-b01, mixed mode)

  • strace ifconfig 2>&1 | grep ioctl

ioctl(4, SIOCGIFCONF, {80, {{"lo", {AF_INET, inet_addr("127.0.0.1")}}, {"wlan0", {AF_INET, inet_addr("192.168.1.101")}}}}) = 0
ioctl(5, SIOCGIFFLAGS, {ifr_name="eth0", ifr_flags=IFF_UP|IFF_BROADCAST|IFF_MULTICAST}) = 0
ioctl(5, SIOCGIFHWADDR, {ifr_name="eth0", ifr_hwaddr=-----------------}) = 0
ioctl(5, SIOCGIFMETRIC, {ifr_name="eth0", ifr_metric=0}) = 0
ioctl(5, SIOCGIFMTU, {ifr_name="eth0", ifr_mtu=1500}) = 0
ioctl(5, SIOCGIFMAP, {ifr_name="eth0", ifr_map={mem_start=0, mem_end=0, base_addr=0, irq=0, dma=0, port=0}}) = 0
ioctl(5, SIOCGIFMAP, {ifr_name="eth0", ifr_map={mem_start=0, mem_end=0, base_addr=0, irq=0, dma=0, port=0}}) = 0
ioctl(5, SIOCGIFTXQLEN, {ifr_name="eth0", ifr_qlen=1000}) = 0
ioctl(4, SIOCGIFADDR, {ifr_name="eth0", ???}) = -1 EADDRNOTAVAIL (Cannot assign requested address)
ioctl(5, SIOCGIFFLAGS, {ifr_name="lo", ifr_flags=IFF_UP|IFF_LOOPBACK|IFF_RUNNING}) = 0
ioctl(5, SIOCGIFHWADDR, {ifr_name="lo", ifr_hwaddr=00:00:00:00:00:00}) = 0
ioctl(5, SIOCGIFMETRIC, {ifr_name="lo", ifr_metric=0}) = 0
ioctl(5, SIOCGIFMTU, {ifr_name="lo", ifr_mtu=16436}) = 0
ioctl(5, SIOCGIFMAP, {ifr_name="lo", ifr_map={mem_start=0, mem_end=0, base_addr=0, irq=0, dma=0, port=0}}) = 0
ioctl(5, SIOCGIFMAP, {ifr_name="lo", ifr_map={mem_start=0, mem_end=0, base_addr=0, irq=0, dma=0, port=0}}) = 0
ioctl(5, SIOCGIFTXQLEN, {ifr_name="lo", ifr_qlen=0}) = 0
ioctl(4, SIOCGIFADDR, {ifr_name="lo", ifr_addr={AF_INET, inet_addr("127.0.0.1")}}) = 0
ioctl(4, SIOCGIFDSTADDR, {ifr_name="lo", ifr_dstaddr={AF_INET, inet_addr("127.0.0.1")}}) = 0
ioctl(4, SIOCGIFBRDADDR, {ifr_name="lo", ifr_broadaddr={AF_INET, inet_addr("0.0.0.0")}}) = 0
ioctl(4, SIOCGIFNETMASK, {ifr_name="lo", ifr_netmask={AF_INET, inet_addr("255.0.0.0")}}) = 0
ioctl(5, SIOCGIFFLAGS, {ifr_name="wlan0", ifr_flags=IFF_UP|IFF_BROADCAST|IFF_RUNNING|IFF_MULTICAST}) = 0
ioctl(5, SIOCGIFHWADDR, {ifr_name="wlan0", ifr_hwaddr=---------------}) = 0
ioctl(5, SIOCGIFMETRIC, {ifr_name="wlan0", ifr_metric=0}) = 0
ioctl(5, SIOCGIFMTU, {ifr_name="wlan0", ifr_mtu=1500}) = 0
ioctl(5, SIOCGIFMAP, {ifr_name="wlan0", ifr_map={mem_start=0, mem_end=0, base_addr=0, irq=0, dma=0, port=0}}) = 0
ioctl(5, SIOCGIFMAP, {ifr_name="wlan0", ifr_map={mem_start=0, mem_end=0, base_addr=0, irq=0, dma=0, port=0}}) = 0
ioctl(5, SIOCGIFTXQLEN, {ifr_name="wlan0", ifr_qlen=1000}) = 0
ioctl(4, SIOCGIFADDR, {ifr_name="wlan0", ifr_addr={AF_INET, inet_addr("192.168.1.101")}}) = 0
ioctl(4, SIOCGIFDSTADDR, {ifr_name="wlan0", ifr_dstaddr={AF_INET, inet_addr("192.168.1.101")}}) = 0
ioctl(4, SIOCGIFBRDADDR, {ifr_name="wlan0", ifr_broadaddr={AF_INET, inet_addr("192.168.1.255")}}) = 0
ioctl(4, SIOCGIFNETMASK, {ifr_name="wlan0", ifr_netmask={AF_INET, inet_addr("255.255.255.0")}}) = 0

ifconfig

$ ifconfig
eth0      Link encap:Ethernet  HWaddr -------------  
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:1695 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1695 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:129949 (129.9 KB)  TX bytes:129949 (129.9 KB)

wlan0     Link encap:Ethernet  HWaddr -------------------  
          inet addr:192.168.1.101  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::-------------- Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8396 errors:0 dropped:0 overruns:0 frame:0
          TX packets:5524 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:3959941 (3.9 MB)  TX bytes:1513934 (1.5 MB)
Deduction answered 17/7, 2013 at 11:47 Comment(11)
Is eth0 configured? Does it show up when you do ifconfig?Elyseelysee
Your code works for me (Ubuntu 12.04 LTS) - it shows lo and eth0Baler
As @Erik said: what is the output of ifconfig? Both ifconfig and the Java API are eventually using the same ioctl call (SIOCGIFCONF), so they should be consistentBaler
@Erik Ekman My machine OS Ubuntu and eth0 show up with ifconfig.Deduction
@Andreas i have the same OS (Ubuntu 12.04 LTS) on on sony-vaio laptop this code show me only (lo,wlan0).Deduction
@KhaledLela Can you update your question with the output from strace -f java Networks 2>&1| grep ioctl (where Networks is the Java class containing your main() method, adjust as necessary), and also add the output from strace ifconfig 2>&1 | grep ioctl? Also, which java version are you using?Baler
Just post ifconfig output as requested several times already...Panteutonism
I try the same code on windows OS and it works fine and show up all interfaces.!Deduction
The output from strace java ... must not be empty - there must be at least some lines with ioctl(), similar to the other trace output. Are you sure that you have properly launched the class (as said, I assumed that your code is in Network.java, default package, so you need a corresponding Network.class file or however you called your class)Baler
possible duplicate of Unable to get all network interfaces with NetworkInterface.getNetworkInterfaces on LinuxArthropod
Found an openjdk bug report: bugs.openjdk.java.net/browse/JDK-8147071Cauchy
B
11

Obviously, I was wrong in the first place: even though both ifconfig and the Java API are using the same ioctl() syscalls, they behave differently.

First of all, the SIOCGIFCONF ioctl() is documented as follows (see http://linux.die.net/man/7/netdevice):

SIOCGIFCONF
    Return a list of interface (transport layer) addresses.
    ...
    The kernel fills the ifreqs with all current L3 interface 
    addresses that are running.

So, the SIOCGIFCONF ioctl() which is used by both ifconfig and the JAVA API only returns the running interfaces. This can also be seen in the strace ifconfig ... output from the question - the very first ioctl only returns lo and wlan0, but not eth0.

Then, where does ifconfig get the eth0 from at all? Checking the ifconfig source code (from the net-tools package on Debian/Ubuntu), we see that ifconfig is not using the result from the ioctl() as the basis for the network device enumeration, but first of all reads the /proc filesystem to determine all network interfaces. Then, it uses the ioctl() syscalls to determine further information about each interface.

Unfortunately, the java.net.NetworkInterface.getByName() method does not even return a network interface object for an unconfigured interface if we explicitly pass the name, like eth0.

Essentially, there remain three different approaches to get the hardware addresses of all devices on Linux:

  • Call ifconfig and parse the output (should be last resort)
  • Implement a JNI library to do the same what ifconfig does (requires an architecture dependent shared library)
  • Read the data directly from the /proc and the /sys filesystems.

All of these approaches are system dependant and not portable. The benefit of the third approach is that it can be implemented in pure Java. The following is a sample implementation of the third approach which worked well in my environment:

static void printHardwareAddresses() throws SocketException {
    if (System.getProperty("os.name").equals("Linux")) {

        // Read all available device names
        List<String> devices = new ArrayList<>();
        Pattern pattern = Pattern.compile("^ *(.*):");
        try (FileReader reader = new FileReader("/proc/net/dev")) {
            BufferedReader in = new BufferedReader(reader);
            String line = null;
            while( (line = in.readLine()) != null) {
                Matcher m = pattern.matcher(line);
                if (m.find()) {
                    devices.add(m.group(1));
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        // read the hardware address for each device
        for (String device : devices) {
            try (FileReader reader = new FileReader("/sys/class/net/" + device + "/address")) {
                BufferedReader in = new BufferedReader(reader);
                String addr = in.readLine();

                System.out.println(String.format("%5s: %s", device, addr));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    } else {
        // use standard API for Windows & Others (need to test on each platform, though!!)
        ...
    }
}
Baler answered 18/7, 2013 at 9:27 Comment(1)
Hey @Andreas I am looking for a similar solution for OS X.. [stackoverflow question here] (https://mcmap.net/q/668101/-java-net-networkinterface-getnetworkinterfaces-not-listing-all-interfaces-for-os-x/2619129). Will really appreciate any help reg this. Thanks.Jehias
E
2

When calling getNetworkInterfaces Java will return

all the interfaces on this machine. Returns null if no network interfaces could be found on this machine.

You are not the only one with this issue. Apparently, on linux Java will return only the interfaces that have an IP Address allocated (i.e. configured adapters).

But from your application point of view (unless you are building a network configuration application) having an interface without an IP address is like not having it at all. You will have to either poll for interfaces or get them every time you access, say, "Network Preferences" in your application.

Ey answered 17/7, 2013 at 17:37 Comment(0)
M
0

Extending @Andreas answer, we could write a small shell script like$ifconfg | grep "Link encap" > some_file and then will have a smaller (only 3 lines) file to parse and pick the first token on each line. Similar thing for getting HWaddress. We will write lesser java code.

Other option could be to use Apache commons IOUtils.toString(new FileInputStream( <file_path>,US_ASCII)) to read the settings. This will eliminate repetitive java I/O code in his solution.

Monreal answered 22/7, 2013 at 15:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.