我如何告诉 ssh 使用非临时 IPv6 地址进行连接?

我如何告诉 ssh 使用非临时 IPv6 地址进行连接?

IPv6 接口(至少具有可路由 IP)通常具有临时 IP 地址,该地址经常更改并且通常用于出站连接以提供更多隐私。

我怎样才能告诉 ssh 不要使用这个地址,而是绑定到给定出站连接尝试的非临时地址?

我知道我可以使用该-b选项绑定到特定的 IP 地址,但这意味着我必须先查找出站接口的 IP 地址。

答案1

在 Linux 上,ssh 需要调用 setsockopt(IPV6_ADDR_PREFERENCES) 来请求特定的地址类型。(Linux setsockopt 文档中没有提到这一点,但代码存在于内核中,似乎符合 RFC 5014 规范。)

由于 OpenSSH 没有任何配置选项可以让你指定地址首选项,因此它必须像这个(仅使用不同的 sockopt)。您可以尝试要求 OpenSSH 开发人员添加这样的选项,但他们通常不想添加 OpenBSD 不支持的任何操作系统功能。

编写脚本来获取正确的地址可能更容易-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);
}

相关内容