Javaでネットワークインターフェースにアクセスする

# TL;DR

* Javaでネットワークインターフェースにアクセスするには、`java.net.NetworkInterface`を使用する
* ネットワークインターフェース名や、`InetAddress`、Macアドレスなどが取得可能

やったことがなかったので。


# 環境

Ubuntu Linux 18.04 LTS上で、

```shell
$ uname -srvmpio
Linux 4.18.0-25-generic #26~18.04.1-Ubuntu SMP Thu Jun 27 07:28:31 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux


$ lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 18.04.4 LTS
Release:	18.04
Codename:	bionic
```

Java 11。

```shell
$ java --version
openjdk 11.0.6 2020-01-14
OpenJDK Runtime Environment (build 11.0.6+10-post-Ubuntu-1ubuntu118.04.1)
OpenJDK 64-Bit Server VM (build 11.0.6+10-post-Ubuntu-1ubuntu118.04.1, mixed mode, sharing)
```

# `java.net.NetworkInterface`

`java.net.NetworkInterface`を使用して、ネットワークインターフェースにアクセスします。

[java.net.NetworkInterface](https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/net/NetworkInterface.html)

ホストのネットワークインターフェースの情報。

```shell
$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
    inet 192.168.200.130/24 brd 192.168.200.255 scope global dynamic noprefixroute ens33
       valid_lft 1737sec preferred_lft 1737sec
    inet6 fe80::6f10:63fc:a80e:7ea0/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: br-72f78aadc23c: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
    inet 172.19.0.1/16 brd 172.19.255.255 scope global br-72f78aadc23c
       valid_lft forever preferred_lft forever
4: br-8dd168bc4c0e: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.1/16 brd 172.18.255.255 scope global br-8dd168bc4c0e
       valid_lft forever preferred_lft forever
5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
    inet 172.22.0.1/16 brd 172.22.255.255 scope global docker0
       valid_lft forever preferred_lft forever
```

サンプルコード。`NetworkInterface.getNetworkInterfaces()`で全ネットワークインターフェースを、またネットワークインターフェース名やインデックス、`InetAddress`でもネットワークインターフェースを取得することができます。

`App.java`

```java
import java.io.IOException;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Collections;
import java.util.List;
import java.util.StringJoiner;

public class App {
    public static void main(String... args) throws SocketException {
        List<NetworkInterface> networkInterfaces = Collections.list(NetworkInterface.getNetworkInterfaces());

        networkInterfaces.forEach(ni -> {
            try {
                System.out.printf(
                        "name = %s, addresses = %s, mac address = %s%n",
                        ni.getName(),
                        Collections.list(ni.getInetAddresses()),
                        formatBinaryToHexString(ni.getHardwareAddress())
                );
            } catch (IOException e) {
                // ignore
            }
        });

        NetworkInterface ni = NetworkInterface.getByName("ens33");
        System.out.printf(
                "name = %s, addresses = %s, mac address = %s%n",
                ni.getName(),
                Collections.list(ni.getInetAddresses()),
                formatBinaryToHexString(ni.getHardwareAddress())
        );
    }

    static String formatBinaryToHexString(byte[] binary) {
        if (binary == null) {
            return "[]";
        }

        StringJoiner joiner = new StringJoiner(":");

        for (byte b : binary) {
            joiner.add(String.format("%02x", b));
        }

        return joiner.toString();
    }
}
```

実行例。

```shell
name = docker0, addresses = [/172.22.0.1], mac address = xx:xx:xx:xx:xx:xx
name = br-8dd168bc4c0e, addresses = [/172.18.0.1], mac address = xx:xx:xx:xx:xx:xx
name = br-72f78aadc23c, addresses = [/172.19.0.1], mac address = xx:xx:xx:xx:xx:xx
name = ens33, addresses = [/fe80:0:0:0:6f10:63fc:a80e:7ea0%ens33, /192.168.200.130], mac address = xx:xx:xx:xx:xx:xx
name = lo, addresses = [/0:0:0:0:0:0:0:1%lo, /127.0.0.1], mac address = []
name = ens33, addresses = [/fe80:0:0:0:6f10:63fc:a80e:7ea0%ens33, /192.168.200.130], mac address = xx:xx:xx:xx:xx:xx
```