IPv6 - Arch Linux 中文维基

跳至內容

# IPv6

出自 Arch Linux 中文维基

相關文章

- IPv6 tunnel broker setup

翻譯狀態：

- 本文（或部分內容）譯自 IPv6，最近一次同步於 2022-11-16，若英文版本有所更改，則您可以幫助同步與翻譯更改的內容。
- 您可以在 ArchWiki 的對應頁面找到本文翻譯的原始修訂歷史。
- 本文可能與英文原文存在出入。

在 Arch Linux 中，IPv6 是默認開啟的。

tldp Linux+IPv6-HOWTO 這篇文章比較舊， 且缺乏維護。不過其涵蓋了本文所提及的許多主題，從基礎的東西講起並且循序漸進到高級配置。而且還有很多命令的例子。初學者可以先讀一讀這篇文章再接著閱讀本文。

## 鄰居發現（Neighbor discovery，ND）

使用 Ping 命令來 ping `ff02::1` 這個多播地址，會得到本地鏈路層的所有主機的響應。需要手動指定接口（`%eth0`）

    $ ping ff02::1%eth0

Ping 完之後，您可以用如下命令來獲取本地子網中的所有主機。

    $ ip -6 neigh

如果您 Ping 的是 `ff02::2` 這個多播地址，則只有網絡中的路由器會響應。

如果您添加一個 `-I your-global-ipv6` 選項，本地鏈路上的主機會以他們的本地鏈路地址來響應。這種情況下可以省略接口。

    $ ping -I 2001:4f8:fff6::21 ff02::1

用下面這個腳本可以 Ping 所有接口上的所有其他主機，並且把你的地址告訴所有人。

    #!/usr/bin/bash
    declare -a l_ifs
    readarray l_ifs < <(/sbin/ip -6 -j address | jq -r '.[] | .ifname ')
    for l_if in ${l_ifs[@]} ; do
     echo $l_if
     declare -a l_addrs
     readarray l_addrs < <(/sbin/ip -6 -j address show dev "$l_if" | \
                            jq -r  '.[0].addr_info[].local')
     for l_addr in ${l_addrs[@]} ; do
       echo $l_addr
       ping -c 4 -6 -I "$l_addr" ff02::1%"$l_if"
     done
    done

## 無狀態地址自動配置 (SLAAC)

想要獲得一個IPv6地址，最簡單的辦法就是用SLAAC。只要您的網絡配置好了「無狀態地址自動配置」（Stateless address autoconfiguration，簡稱SLAAC），您的設備就會自動根據路由器廣播（Router Advertisement，RA）的前綴為自己配置一個地址。既不需要進一步配置，也不需要專門的軟體（如DHCP客戶端）

### 客戶端配置

如果您正在使用 netctl，您要做的只是往接口配置文件裡加上這麼一行：

    IP6=stateless

如果您使用的是 NetworkManager，那麼只要網絡內有路由器廣播，它就會自動配置上 IPv6 地址。

不過需要注意的是，SLAAC只有在網絡允許 IPv6 ICMP 包通過的時候才能工作。所以你需要在客戶端防火牆上允許 `ipv6-icmp` 類型的數據包傳入。如果您用的是 Simple stateful firewall/iptables，加上下面這行就可以了：

    -A INPUT -p ipv6-icmp -j ACCEPT

如果您用的是其他防火牆，請參考對應的文檔來放行 `ipv6-icmp` 數據包。

如果你選擇的網絡管理方案不支持通過SLAAC配置DNS（比如netctl），那麼你可以考慮用ndisc6包包裡的rdnssd(8)命令來配置DNS。

### 路由器（網關）配置

要正確給網絡內的客戶端分配 IPv6，我們要用到一個廣播守護進程，一般是radvd包。其配置過程其實相當簡單。參考下面的配置來編輯 `/etc/radvd.conf`文件。

    # 把LAN替换为你实际的局域网接口
    interface LAN {
      AdvSendAdvert on;
      MinRtrAdvInterval 3;
      MaxRtrAdvInterval 10;
      prefix ::/64 {
        AdvOnLink on;
        AdvAutonomous on;
        AdvRouterAddr on;
      };
    };

以上配置會讓客戶端自己從 /64 地址段中選擇地址來使用。請注意如果配置了 `prefix ::/64`，RADVD會向區域網廣播那個接口上的所有可用的前綴。如果您想要廣播指定的前綴，請手動指定，比如 `prefix 2001:DB8::/64`。`prefix` 節可以根據需要多次重複來廣播多個不同前綴。

您可以通過 RDNSS 功能向客戶端廣播 DNS，以 Google DNS 為例，配置如下：

    RDNSS 2001:4860:4860::8888 2001:4860:4860::8844 {
    };

網關必須在所有鏈上允許 `ipv6-icmp` 類型數據包通過。以 Simple stateful firewall/iptables 為例：

    -A INPUT -p ipv6-icmp -j ACCEPT
    -A OUTPUT -p ipv6-icmp -j ACCEPT
    -A FORWARD -p ipv6-icmp -j ACCEPT

根據其他防火牆前端進行相應的調整，最後別忘了激活 `radvd.service` 服務。

## 隱私拓展

當一個客戶端通過 SLAAC 獲得一個地址時，其 IPv6 地址是經過客戶端網絡接口廣播的前綴和 MAC 地址計算而得出的。這可能會引起隱私問題，因為別人可以輕易通過 IPv6 SLAAC 地址反推客戶端 MAC。為了解決這個問題，RFC 4941 中提出了 IPv6 隱私拓展標準。啟用隱私擴展後，內核會生成一個臨時地址，這個地址是原來的 SLAAC 地址經過二次計算得出的隨機地址。當主動連接到遠程伺服器時，會優先選擇使用私有地址，從而幫助隱藏原始的 SLAAC地址。啟用隱私擴展的步驟如下:

向 `/etc/sysctl.d/40-ipv6.conf` 中添加如下內容：

    # Enable IPv6 Privacy Extensions
    net.ipv6.conf.all.use_tempaddr = 2
    net.ipv6.conf.default.use_tempaddr = 2
    net.ipv6.conf.nic0.use_tempaddr = 2
    ...
    net.ipv6.conf.nicN.use_tempaddr = 2

上面的 `nic0` 到 `nicN` 是你的網絡接口。你可以參考網絡配置#Listing network interfaces 來列出你的設備上的接口。 `all.use_tempaddr` 或者 `default.use_tempaddr` 參數對於執行 sysctl 設置時已經存在的接口無效，也就是說不會即時生效。

不過當您重啟設備之後，隱私拓展應該就會生效了。

### dhcpcd

dhcpcd 的默認配置已經包括了 `slaac private`，這會啟用 RFC 7217 中定義的「穩定的私有IPv6地址而不是基於硬體的地址」功能。因此，您無需修改任何設置，除非您希望更頻繁地獲得新的隨機地址，而不僅在連接到新網絡的時候改變IPv6地址。您還可以設置 `slaac hwaddr` 來使用普通的基於 MAC 生成的固定 IPv6 後綴。

### NetworkManager

您可以修改 NetworkManager 的全局配置文件 NetworkManager.conf(5) 或連接配置中的 `ipv6.ip6-privacy` 選項，來決定是否啟用 IPv6 隱私拓展。如果全局配置和連接配置都沒有設置該選項，NetworkManager 會根據 `/proc/sys/net/ipv6/conf/default/use_tempaddr` 內核參數來決定。

如果您想明確默認啟用 IPv6 隱私拓展，請在 NetworkManager.conf(5) 中添加以下內容：

    /etc/NetworkManager/conf.d/ip6-privacy.conf

    [connection]
    ipv6.ip6-privacy=2

然後應用配置並重新連接所有活動接口。

想要為每一個使用 NetworkManager 管理的接口單獨設置 IPv6 隱私拓展功能，請編輯其對應的 `/etc/NetworkManager/system-connections/` 目錄下的 keyfile，並把 `ip6-privacy=2` 添加到 `[ipv6]` 一節下方，示例如下：

    /etc/NetworkManager/system-connections/example_connection.nmconnection

    ...
    [ipv6]
    method=auto
    ip6-privacy=2
    ...

最後，重新加載連接配置並再次連接。

注意：儘管隱私拓展生成的 `scope global temporary` IPv6 地址看上去永遠不會被更新（在其 `valid_lft` 所顯示的生命周期內，該地址永遠不會變為 `deprecated` 狀態），但經過較長時間的驗證，這個地址 確實 會發生變化。

### systemd-networkd

systemd-networkd 同樣不遵守 `/etc/sysctl.d/40-ipv6.conf` 中配置的 `net.ipv6.conf.xxx.use_tempaddr` 內核參數，除非您在 .network 文件中指定 `IPv6PrivacyExtensions` 選項的值為 `kernel`。

不過 systemd-networkd 遵守其他 IPv6 隱私拓展的內核參數，比如：

    net.ipv6.conf.xxx.temp_prefered_lft
    net.ipv6.conf.xxx.temp_valid_lft

注意：`temp_prefered_lft` 才是正確的變量名，「preferred」應該是拼錯了

請參考 systemd-networkd 和 systemd.network(5) 以了解更多信息。

### ConnMan

在服務文件（比如 `/var/lib/connman/service/settings`）中設置：

    IPv6.privacy=preferred

請參考 ConnMan 以了解更多信息。

## 穩定的隱私地址

另外一個選擇，是使用 RFC 7217 中定義的穩定隱私地址。它可以在不暴露 MAC 地址的情況下固定住網絡中的 IPv6 地址。

Another option is a stable private IP address (RFC 7217). This allows for IPs that are stable within a network without exposing the MAC address of the interface.

以 `wlan0` 接口為例，使用以下命令來讓內核為其生成一個密鑰：

    # sysctl net.ipv6.conf.wlan0.addr_gen_mode=3

把接口關閉再啟用，然後運行 `ip addr show dev wlan0`，您應該會看到每個 IPv6 地址旁邊會有 `stable-privacy` 標誌。內核已經為該接口生成了一個 128 位的密鑰用於產生穩定 IPv6 地址，您可以運行 `sysctl net.ipv6.conf.wlan0.stable_secret` 來查看這一密鑰。我們需要固定這個密鑰以讓他每次重啟後都獲得同樣的地址，所以請在 `/etc/sysctl.d/40-ipv6.conf` 中進行如下配置：

    # Enable IPv6 stable privacy mode
    net.ipv6.conf.wlan0.stable_secret = 刚才查看的密钥
    net.ipv6.conf.wlan0.addr_gen_mode = 2

注意：`stable-privacy` 標誌 不會 被應用到由 dhcpcd 獲得的 IPv6 地址上

### NetworkManager

NetworkManager 不遵守以上設置，但是它默認已經啟用了穩定隱私地址。[1][2]

## 靜態地址

有些情況下使用靜態地址可以增強安全性。使用SLAAC分配動態地址時，你的計算機的地址會由其網卡MAC推算出，這不利於安全，因為即使地址的網絡號改變，你的電腦依然可以被追蹤到。

要想用netctl分配一個靜態地址，可以參照`/etc/netctl/examples/ethernet-static`。如下的部分尤其重要：

    ...
    # For IPv6 static address configuration
    IP6=static
    Address6=('1234:5678:9abc:def::1/64' '1234:3456::123/96')
    Routes6=('abcd::1234')
    Gateway6='1234:0:123::abcd'

注意：如果你只有IPv6連接，那麼你要給出IPv6的DNS伺服器，例如：

    DNS=('6666:6666::1' '6666:6666::2')

如果你的ISP沒有告訴你IPv6的DNS伺服器地址，並且你也沒有自己的伺服器，你可以從resolv.conf這篇文章中選一個。

## IPv6與PPPoE

PPPoE的軟體包`pppd`提供了對PPPoE之上的IPv6的支持（前提是你的ISP和數據機支持）。只需要將如下內容加入`/etc/ppp/pppoe.conf`：

     +ipv6

如果你使用netctl，那麼就向你的netctl配置文件加入如下內容：

     PPPoEIP6=yes

## 地址委派 (DHCPv6-PD)

注意：這個部分是針對自行使用配置網關的內容，不是客戶端。如果你使用從市場購得的路由器，請查閱其附帶的文檔以開啟地址委派。

地址委派是一種常見的 IPv6 部署方式，被許多 ISP 所採用。具體的做法是將一個地址前綴分配給用戶（區域網），即路由器配置為將不同的前綴分配給不同的子網；ISP 通過 DHCPv6 將地址前綴（通常是`/56`或`/64`）分發出去，DHCP 客戶端再將前綴分配給區域網。對於一個擁有兩個網卡的簡單網關來說，它的工作就是將從 WAN 口（或虛擬接口，比如ppp）獲取的前綴分配給區域網。

DHCPv6 客戶端需要在 UDP 546 接口上接受傳入的連接。對於基於 nftables 的防火牆，可以編輯 `/etc/nftables.conf`：

    table inet filter {
      chain input {
        udp dport dhcpv6-client accept
        ...
      }
    ...
    }

### 使用dhcpcd

Dhcpcd在 IPv4 之外也提供了一個完整的支持 DHCPv6-PD 的客戶端。如果你使用 `dhcpcd`，需要修改 `/etc/dhcpcd.conf`。你可能已經在用dhcpcd來配置 IPv4,，所以只需要對現有的配置進行小幅修改：

    duid
    noipv6rs
    waitip 6
    # Uncomment this line if you are running dhcpcd for IPv6 only.
    #ipv6only

    # use the interface connected to WAN
    interface WAN
    ipv6rs
    iaid 1
    # use the interface connected to your LAN
    ia_pd 1 LAN
    #ia_pd 1/::/64 LAN/0/64

這種配置下，客戶端會從`WAN`接口獲取一個前綴，分配給`LAN`接口。 如果ISP分配的是`/64`的地址，你需要用第二個`ia_pd`選項。 這也會禁用除`WAN`接口之外的所有路由器請求。

提示：查閱手冊頁`dhcpcd(8)`與`dhcpcd.conf(5)`獲得更多信息。

### 使用WIDE-DHCPv6

WIDE-DHCPv6是原本由KAME計劃開發的DHCPv6開源實現。它在AUR中：wide-dhcpv6AUR。

如果你使用`wide-dhcpv6`，修改`/etc/wide-dhcpv6/dhcp6c.conf`：

    # use the interface connected to your WAN
    interface WAN {
      send ia-pd 0;
    };

    id-assoc pd 0 {
      # use the interface connected to your LAN
      prefix-interface LAN {
        sla-id 1;
        sla-len 8;
      };
    };

注意：`sla-len`應設置為滿足`(WAN-prefix) + (sla-len) = 64`的值。這裡示範的情況是針對一個長度`/56`的前綴，56+8=64。對於前綴長度`/64`的網絡，`sla-len`應為`0`。

要啟用或運行wide-dhcpv6，使用如下命令。把`WAN`改為連接到ISP的網卡:

    # systemctl enable/start dhcp6c@WAN.service

提示：查閱手冊頁`dhcp6c(8)`與`dhcp6c.conf(5)`獲取更多信息。

### systemd-networkd

配置您的上游(wan)和下游(lan)接口。這將在運行 DHCPv6 客戶端的接口上啟用 DHCPv6-PD，並通過 IPv6 路由廣播在下游網絡中分發委派的地址前綴。

    /etc/systemd/network/wan.network

    [Network]
    # Use 'yes' instead of 'ipv6' for both ipv4 and ipv6.
    DHCP=ipv6

    /etc/systemd/network/lan.network

    [Network]
    IPv6SendRA=yes
    DHCPv6PrefixDelegation=yes

### 其他客戶端

dhclient 也可以請求前綴；但想要把整個或者部分前綴分配到接口上則需要使用 dhclient 退出腳本來完成。請參考 https://github.com/jaymzh/v6-gw-scripts/blob/master/dhclient-ipv6 中的例子。

## NAT64

Wikipedia:NAT64 是讓只有 IPv6 地址的主機通過使用 NAT 來和 IPv4 主機通信的過渡機制。

Linux 內核並不原生支持 NAT64，但您可以使用以下這些軟體包來添加 NAT64 支持：

- Jool — SIIT and NAT64 for Linux

  https://nicmx.github.io/Jool/ || jool-dkmsAUR, jool-toolsAUR

- TAYGA — NAT64 daemon (unmaintained)

  http://www.litech.org/tayga/ || taygaAUR

## 禁用 IPv6

注意：Arch直接將IPv6支持編譯進內核，因此不能禁用對應的內核模塊。

### 關閉 IPv6 功能

如果您遇到一些問題，可以試著向內核參數加入 `ipv6.disable=1` ，來完全關閉 IPv6 功能， 參考內核參數來了解更多信息.

此外，只加入`ipv6.disable_ipv6=1`內核參數可以保留IPv6功能，但不會向網卡分配IPv6地址。

也可以通過向`/etc/sysctl.d/40-ipv6.conf`加入如下配置來避免系統給網卡分配IPv6地址：

    # Disable IPv6
    net.ipv6.conf.all.disable_ipv6 = 1
    net.ipv6.conf.nic0.disable_ipv6 = 1
    ...
    net.ipv6.conf.nicN.disable_ipv6 = 1

重啟 `systemd-sysctl.service` 單元來應用上述設置。

注意你必須在這裡清楚地列出所有不需要分配IPv6地址的網卡，僅僅設置`all.disable_ipv6`並不會立刻對已經連接的網卡起作用。

注意：如果通過 sysctl 禁用IPv6， 你應該在`/etc/hosts`中刪除所有的IPv6主機，否則當你使用主機名連接它們的時候會解析到不通的IPv6地址

### 其他應用程式

在內核中關閉 IPv6 功能不會阻止應用程式嘗試使用 IPv6。多數情況下，這樣不會有問題，但如果你發現程序無法正常運行，你應該查閱該應用程式的手冊頁，以找到關閉 IPv6 的合適方法。

#### dhcpcd

dhcpcd會依然嘗試發送 IPv6 路由器請求。要禁用這種行為，可以依照其手冊頁`dhcpcd.conf (5)`，向`/etc/dhcpcd.conf`加入如下內容：

    noipv6rs
    noipv6

#### NetworkManager

如果要禁用 NetworkManager 的 IPv6 功能，右鍵點擊網絡狀態圖標，然後選擇配置網絡連接 > 有線以太網 > 網絡連接名稱 > 編輯 > IPv6 > 方法 > 忽略/已禁用然後點擊應用。

你也可以通過命令行來設置，先輸入：

    # nmcli connection modify ConnectionName ipv6.method "disabled"

然後再重啟連接：

    # nmcli connection up ConnectionName

要確認設置是否被應用，使用 `ip address show` 看看還有沒有顯示 IPv6 地址（inet6）。或者檢查 `/proc/sys/net/ipv6/conf/interface/disable_ipv6` 這個內核參數，其值應該為 1。

#### ntpd

依照Systemd#Drop-in files，修改`ntpd.service`的啟動方式。

    # systemctl edit ntpd.service

這樣會產生一個drop-in snippet，替代原有的`ntpd.service`來加載ntpd。參數`-4`關閉了ntpd的IPv6支持。向drop-in snippet中加入如下內容：

    [Service]
    ExecStart=
    ExecStart=/usr/bin/ntpd -4 -g -u ntp:ntp

第一行清除了之前的`ExecStart`配置，接下來的一行將該配置設置為帶有`-4`參數的ntpd。

#### GnuPG

在 dirmngr 配置文件中設置如下參數：

    ~/.gnupg/dirmngr.conf

    disable-ipv6

然後重啟 `dirmngr.service` 服務.

#### sshd

修改 `sshd_config` 來讓 sshd 只使用 IPv4：

    /etc/ssh/sshd_config

    AddressFamily inet

然後重啟 `sshd.service` 服務

#### systemd-timesyncd

有時 Systemd-timesyncd 會嘗試查詢IPv6時間伺服器，即使IPv6已被禁用。這可能導致系統時鐘未更新，日誌顯示類似以下錯誤：

    systemd-timesyncd[336]: Failed to set up connection socket: Address family not supported by protocol

`systemd timesyncd` 在其「狀態」中會顯示嘗試連接 IPv6 地址的記錄，類似於：

    Status: "Connecting to time server [2001:19f0:8001:afd:5400:1ff:fe9d:cba]:123 (2.pool.ntp.org)"

根據 FS#59806, 只有 2.ntp.org 池支持 IPv6。所以將 `2.arch.pool.ntp.org` 和 `2.pool.ntp.org` 從配置文件 `/etc/systemd/timesyncd.conf` 的 NTP 和 FallbackNTP 部分中刪去即可避免這一現象。

### systemd-networkd

networkd 支持按接口禁用IPv6。當網絡單元的 `[Network]` 部分的 `LinkLocalAddressing=ipv4` 或 `LinkLocalAddressing=no` 時，networkd不會嘗試在匹配的接口上配置IPv6。

然而，請注意，即使在使用上述選項時，如果 IPv6 未被全局禁用，networkd 仍會收到路由器通告。如果接口未接收到IPv6流量（例如，由於 sysctl 或 ip6tables 設置），它將保持在配置狀態，並可能導致等待網絡完全配置的服務超時。為了避免這種情況，還應在 `[Network]` 部分設置 `IPv6AcceptRA=no` 選項。

## 參見

- IPv6 — kernel.org documentation
- IPv6 temporary addresses — a summary about temporary addresses and privacy extensions
- IPv6 prefixes — a summary of prefix types
- net.ipv6 options — documentation of kernel parameters

分類：​

- 網絡

IPv6
新增話題