IPv6の近隣探索について：ついでにIPv6でarping的なことをするコマンドを紹介したい

この記事は[SFC-RG Advent Calendar 2018](https://qiita.com/advent-calendar/2018/sfc-rg)の1日目です。

# 概要

ipv6の近隣探索(Neighbor Discovery for IP version 6)を利用するためのUNIXコマンドって聞いたことないよな〜って思って調べてみたら普通にあったけどあんまり知名度高くなさそうだったから書いとく。
これだけだとアドベントカレンダーに載せるにはあまりに忍びないので近隣探索について知ってることを書いた。

この記事はこのような人を対象にしています。

* ipv6アドレスからMACアドレスが知りたい人
* ICMP Echo Requestに答えない不躾なホストを探したい人
* 珍しいコマンドを知りたいオタク

## 検証環境
```bash:~/
$ cat /etc/issue
Ubuntu 18.04.1 LTS \n \l
```

# 本題

## ipv4の場合
ipv4の世界では同一サブネットのIPアドレスからMACアドレスを探すために、arpと呼ばれるプロトコルを利用して同一リンク内にブロードキャストパケットを送信する手法を採用している。
Linuxではデバイスが所持しているIP/MACの対応表(ARPテーブル)は以下のようなコマンドで見ることができる。

```bash:~/
# 古くは
$ arp -n
# 最近は
$ ip neigh
```

主にネットワークのトラブルシューティングをする際にIPアドレスからMACアドレスを知りたいというニーズがある。少なくとも私にはちょくちょくある。また、ping(ICMP Echo Request)に答えないホスト(WindowsとかFWがきついホストとか）の生存確認を行いたい時もある。そんなときに、```arping```というコマンドを利用することがある。

```bash:~/
$ sudo  arping 10.200.0.1
ARPING 10.200.0.1
60 bytes from MACアドレスですよ〜〜 (10.200.0.1): index=0 time=2.435 msec
60 bytes from MACアドレスですよ〜〜 (10.200.0.1): index=1 time=2.104 msec
^C
--- 10.200.0.1 statistics ---
2 packets transmitted, 2 packets received,   0% unanswered (0 extra)
rtt min/avg/max/std-dev = 2.104/2.269/2.435/0.166 ms
```

## ipv6の場合
ipv6の世界にはarpは無い。その代わりに同一リンク上のipv6アドレスからMACアドレスを探すために、**近隣探索**(Neighbor Discovery for IP version 6)と呼ばれるプロトコルを用いる。これはIPv4のICMPをより広範に拡張したICMPv6上で動作する。MACアドレス解決の他に、デフォゲ探し(router solicitation / router advertisement)のような、IPv4で他のプロトコルに頼っていた事案も近隣探索によって解決する。
以下のコマンドからデバイスの近隣探索テーブルを確認することができる。

```bash:~/
$ ip -6 neigh
別ホストのIPv6アドレスですよ〜〜〜 dev wlp2s0  FAILED
ルーター１のIPv6アドレスですよ〜〜〜 dev wlp2s0 lladdr ルーター1のMACアドレス router REACHABLE
ルーター２のIPv6アドレスですよ〜〜〜 dev wlp2s0 lladdr ルーター2のMACアドレス router STALE
```

IPv4でのARPテーブルではキャッシュの保持時間(15秒~45秒）を設定し、古い物を破棄することでエントリーの正当性を保証していたが、IPv6の近隣探索では各ホストの状態(REACHABLE,STALEなど)を記録する要素を追加して管理する手法を採用している。これらの情報も```ip -6 neigh```で確認可能である。

もちろん、一度も通信を行っていないホストの情報はここには記載されない。
しかしながら、IPv6の世界でもIPアドレスからMacアドレスを知りたいニーズは存在している...と思う。
どうやらIPv6でも```arping```のように簡単に近隣探索できるコマンドがあるらしい。

## IPv6版arping: ndisc6
そんな素敵なコマンドが**ndisc6**である。
残念なことにip-utilsにセットに入っていたりしないので知らない人も多いはず。
普通にaptでinstall可能。もちろん公式リポジトリからソースコードも落とせるのでこだわりのある人はビルドしてみてください。

```bash:~/
$ sudo apt install ndisc6
```
### 使い方
#### 近隣探索：ndisc6
一番シンプルに近隣要請を行う方法。

```bash:~/
$ ndisc6 【IPv6アドレス】 【対象とするインターフェース名】
```

#### ルーター探索：rdisc6
また、姉妹コマンド**rdisc6**を使うことでルーター要請を行うことができる。同一リンク上に複数ルーターが居る場合は複数出てくる。
結構詳しく色々教えてくれて楽しい。

```bash:~/
$ rdisc6 wlp2s0
Soliciting ff02::2 (ff02::2) on wlp2s0...

Hop limit                 :           64 (      0x40)
Stateful address conf.    :           No
Stateful other conf.      :          Yes
Mobile home agent         :           No
Router preference         :       medium
Neighbor discovery proxy  :           No
Router lifetime           :         1800 (0x00000708) seconds
Reachable time            :       300000 (0x000493e0) milliseconds
Retransmit time           :        10000 (0x00002710) milliseconds
 Source link-layer address: 00:1D:70:7D:EF:C7
 MTU                      :         1500 bytes (valid)
 Prefix                   : プレフィックスだよ〜::/64
  On-link                 :          Yes
  Autonomous address conf.:          Yes
  Valid time              :      2592000 (0x00278d00) seconds
  Pref. time              :       604800 (0x00093a80) seconds
 from fe80::ルーターだよ〜

```



# まとめ
これでIPv6でも```arping```的なことができる。

```bash:~/
$ ndisc6 【IPv6アドレス】 【対象とするインターフェース名】
```

# References
- [RFC 4861](https://tools.ietf.org/html/rfc4861)
- [NDisc6 : IPv6 diagnostic tools for Linux and BSD](https://www.remlab.net/ndisc6/)