![如何告訴 ssh 使用非臨時 IPv6 位址進行連線?](https://rvso.com/image/1703325/%E5%A6%82%E4%BD%95%E5%91%8A%E8%A8%B4%20ssh%20%E4%BD%BF%E7%94%A8%E9%9D%9E%E8%87%A8%E6%99%82%20IPv6%20%E4%BD%8D%E5%9D%80%E9%80%B2%E8%A1%8C%E9%80%A3%E7%B7%9A%EF%BC%9F.png)
IPv6 介面(至少具有可路由的 IP)通常有一個臨時 IP 位址,該位址經常更改,通常用於出站連接,以提供更多隱私。
我該如何告訴 ssh 不要使用此位址,而是針對給定的出站連線嘗試綁定到非臨時位址?
我知道我可以使用該-b
選項綁定到特定的 IP 位址,但這意味著我必須先查找出站介面的 IP 位址。
答案1
在 Linux 上,ssh 需要呼叫 setsockopt(IPV6_ADDR_PREFERENCES) 來請求特定的位址類型。 (Linux setsockopt 文件中沒有提到這一點,但程式碼存在於核心中,並且似乎符合 RFC 5014 規範。)
由於 OpenSSH 沒有任何設定選項可以讓您指定位址首選項,因此它必須是像這樣的 hack這個(僅適用於不同的 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);
}