非一時 IPv6 アドレスを使用して ssh に接続するように指示するにはどうすればよいですか?

非一時 IPv6 アドレスを使用して ssh に接続するように指示するにはどうすればよいですか?

IPv6 インターフェイス (少なくともルーティング可能な IP を持つ) には通常、一時的な IP アドレスがあり、これは頻繁に変更され、通常はプライバシーを強化するために送信接続に使用されます。

このアドレスを使用せず、代わりに特定の送信接続試行に対して非一時アドレスにバインドするように ssh に指示するにはどうすればよいですか?

特定の IP アドレスにバインドするオプションを使用できることはわかっています-bが、そのためにはまず送信インターフェイスの IP アドレスを検索する必要があります。

答え1

Linux では、特定のアドレス タイプを要求するには、ssh は setsockopt(IPV6_ADDR_PREFERENCES) を呼び出す必要があります。(これは Linux setsockopt ドキュメントには記載されていませんが、コードはカーネル内に存在し、RFC 5014 仕様と一致しているようです。)

OpenSSHにはアドレス設定を指定できる設定オプションがないので、次のようなハックが必要になります。これです(異なる sockopt のみ)。OpenSSH 開発者にそのようなオプションを追加するように依頼することもできますが、通常、OpenBSD がサポートしていない OS 機能を追加することは望んでいません。

の正しいアドレスを取得するには、スクリプトを記述する方が簡単でしょう-b。たとえば、Linux の場合は、次のように記述できますip | jq

addr=$(ip -json -6 addr ls dev eno1 scope global \
      | jq -r ".[].addr_info[]|select(.local)|select(.temporary|not)|.local")

ssh -b $addr ...

あるいは、一時アドレス(プライバシー拡張機能)を完全にオフにします。

しかし、運試しをしたい場合はLD_PRELOAD、これをテストすることができます (私はまったくテストしていませんが、効果が出るには遅すぎる可能性があります)。

/* gcc -shared -o ipv6pref.so ipv6pref.c */
/* LD_PRELOAD="$HOME/ipv6pref.so" ssh whatever */

#define _GNU_SOURCE
#include <dlfcn.h>
#include <err.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <sys/socket.h>

int setsockopt(int fd, int level, int name, const void *value, socklen_t len)
{
    static int (*real_setsockopt)(int, int, int, const void *, socklen_t);
    uint32_t flags = IPV6_PREFER_SRC_PUBLIC;
    int r;

    if (!real_setsockopt)
        real_setsockopt = dlsym(RTLD_NEXT, "setsockopt");
    
    if ((level == SOL_IP && name == IP_TOS) ||
        (level == SOL_IPV6 && name == IPV6_TCLASS))
    {
        /* This is probably the TCP socket that will be used for SSH. */
        r = real_setsockopt(fd, IPPROTO_IPV6, IPV6_ADDR_PREFERENCES, &flags, sizeof flags);
        if (r != 0)
            warn("Could not set address preference");
    }

    return real_setsockopt(fd, level, name, value, len);
}

関連情報