リンクローカルアドレスとssh

経緯

自宅サーバーは基本的にIPv6のリンクローカルアドレスでアクセスしている。

このリンクローカルアドレスというのは、(物理インターフェースの場合)NIC固有のMACアドレスから生成されるため、ネットワークに依存しないという特徴がある。

具体的な運用上のメリットとしては

実際に今回メインの回線が繋がらなくなったものの、自宅の機器をすべてもう一つの回線に切り替える1ことで問題なく機能している様子。2

ただ、あとになってsshが直接繋げないという問題が発覚したため、調べた。3

前提

sshのバージョンについて

$ ssh -V
OpenSSH_8.4p1, OpenSSL 1.1.1h  22 Sep 2020

結論

リンクローカルアドレスはどのNICも同じネットワークに見えてしまうため、どのインターフェイスから通信を送るかを指定する必要がある

Zone indexを用いたやり方

以下のようにリンクローカルアドレスの後ろに%zone index(詳しくは後述)をつける。

ssh user@fe80::1111:2222:3333:4444%eth0

これを~/.ssh/configに書く際は以下のようにパーセントを2つにする必要がある

Host example-server
    User            user
    HostName        fe80::1111:2222:3333:4444%%eth0

Zone indexについて補足

Bind interfaceを用いたやり方

宛先のインターフェースを特定できればいいのであれば、わざわざzone indexという特殊な書き方をしなくても他に方法があるのではないか?

そう思って探したらbind interfaceというオプションがあったので試してみたら接続できた。

コマンドで指定する場合

ssh -B eth0 user@fe80::1111:2222:3333:4444

configで設定する場合

Host example-server
    User            user
    HostName        fe80::1111:2222:3333:4444
    BindInterface   eth0

このほうがホストのアドレスとクライアントのインターフェースを切り分けられるので良さそう。

実際の設定例

以下のように分けた。

~/.ssh/config

Include ~/.ssh/conf.d/*.conf

~/.ssh/conf.d/interface.conf

Host *-locallink
    BindInterface   eth0

~/.ssh/conf.d/interface.conf

Host example1-locallink
    User            user
    HostName        fe80::1111:2222:3333:4444
Host example1-vpn
    (中略)
Host example2-locallink
    (中略)

このような感じでinterface.confだけクライアント別に作成し、ほかは共通にできるようにした。

反省

wireguardが問題なく動いてたから油断してたけど、sshに限らずほかもちゃんと指定したほうが良さそう。

参考

IPv6アドレス#リンクローカルアドレスとゾーンインデックス - wikipedia

Debian Bug report logs - #616610 openssh-client: ssh config does not like IPv6 link local address as hostname anymore


  1. アパートが契約した無料インターネット回線。この回線、自分が入居した当初にはなかったので当時自分で契約した回線がまだ契約が続いていて、そのままメインで使っている。無駄だと思っていたのに役立つときが来るとは思わなかった。 ↩︎

  2. 問題ないといってもリンクローカルアドレスで確実に問題なく機能していると言えるのはWireguad VPNのエンドポイントだけで、他の通信はほぼVPNで別に割り振ったIPアドレスでアクセスしている。 ↩︎

  3. 通常はsshも上記のようにVPN経由でアクセスしていたので問題なかった。とはいえwireguardなどのサービスを設定するのにsshが必要なので、いざというときに直接アクセスできないのは困る。 ↩︎