IPv6無狀態地址自動配置(SLAAC)-常見問題

苍然满关中發表於2024-08-17

SLAAC如何工作?

主機在啟動或介面UP後,傳送路由器祈求(Router Solicitation,RS),路由器收到此訊息後,回覆路由器宣告(Router Advertisement,RA)。此宣告可能是單播給主機的,也可能是多播的,取決於路由器當前的狀態(見下文)。

路由器在RA中設定M位和O位,針對這兩個標誌位,解釋如下:

M位:“Managed address configuration”標誌。值為1時,表示地址可以透過DHCPv6方式獲取。若M標識位置1,O標誌位是冗餘的,可以被忽略,因為DHCPv6可以提供所有的配置資訊。

O位:“Other configuration”標誌。值為1時,表示除地址外其它的配置資訊可是透過DHCPv6方式獲取。

若使用SLAAC,則RA中會設定M=0,O=1,指示主機透過SLAAC來配置地址,其它資訊,如DNS伺服器等,可以透過DHCPv6方式獲取(也可以透過單個RA來一次性的獲取字首和DNS伺服器資訊,關於獲取DNS的方式,請參考下文)。RA中同時會攜帶一個字首資訊選項(Prefix Information Option,PIO),指示主機應該使用的字首。

主機收到RA後,解析訊息,使用RA中指定的字首(一般字首長度為64位),與本地生成的64位介面ID組合,生成介面的128位IP地址。在經過重複地址檢測(DAD)後,確認地址可用。至此,主機使用SLAAC來配置自身的過程已經完成,就可以使用IPv6地址進行通訊了。

與IPv4類似,主機要想訪問IPv6網際網路,還需要知道預設路由器(閘道器)資訊和DNS伺服器資訊。

獲取預設路由器(閘道器)也是透過RA來完成的,詳見下文。

IPv6 DNS伺服器資訊的重要性不高,沒有此資訊也不會影響主機使用IPv6訪問網際網路,原因是,主機一般是雙棧的,可以使用IPv4來查詢AAAA記錄。

IPv6如何發現預設路由器(閘道器)?

主機收到有效的路由器宣告(RA)訊息後,從訊息中提取源地址並新增到自己的預設路由器列表中(參考RFC4861第6.3.4節)。

主機對路由器宣告(RA)訊息進行如下有效性檢查(參考RFC4861第6.1.2節):

  1. 源IP地址是鏈路本地地址。路由器必須使用其鏈路本地地址作為路由宣告和重定向訊息的源地址,以便主機可以唯一識別路由器。
  2. IP頭部的跳數限制欄位值是255,報文不能是被其它路由器轉發過的。
  3. ICMP頭部的校驗和有效。
  4. ICMP頭部的程式碼(Code)欄位值為0。
  5. ICMP報文的長度為16位元組或更長。
  6. 攜帶的所有選項的長度欄位值大於0。

路由器宣告(RA)訊息中包含Router Lifetime欄位,指示路由器的有效期,當收到此欄位值為0的RA時,主機從預設路由器列表中刪除該路由器。

主機會針對預設路由器的地址進行鄰居發現來解析其MAC地址。

鄰居發現的過程

鄰居發現主要有3種用途:

  1. 地址解析;
  2. 可達性探測;
  3. 重複地址檢測(DAD)

本節主要講述第一種用途。

與IPv4類似,主機在與同網段其他主機或閘道器通訊時,需要學習對端的MAC地址。在IPv4中,這是透過ARP來實現的,在IPv6中,這個過程叫鄰居發現。

鄰居發現包括2個報文,即鄰居祈求(Neighbor Solicitation,RS)和鄰居宣告(Neighbor Advertisement,NA)。類似IPv4中的ARP請求和應答。

主機首先傳送NS,其中目的地址是“請求節點多播地址”,源地址是自身介面的地址。在Target Address欄位中包含要解析的目標地址。必須攜帶源鏈路層地址(Source Link-layer Address)選項,包含自己的鏈路層地址。

思考:為什麼NS的目的地址是“請求節點多播地址”,而不是直接使用目標地址?

“請求節點多播地址”的格式為“FF02:0:0:0:0:1:FFXX:XXXX”,其計算方式是取目標單播/任播地址的低24位,將其附加到字首FF02:0:0:0:0:1:FF00::/104之後。

目標主機收到NS後,回覆NA,攜帶目標鏈路層地址(Target link-layer address)選項,包含對應的鏈路層地址。

主機收到NA後,地址解析已完成。後續就可以向目標主機傳送報文了。

什麼是重複地址檢測(DAD)?

主機在使用RA中宣告的字首和自己生成的介面ID組合生成完整的IPv6地址之後,需要先對該地址進行重複地址檢測,檢測透過,確認無衝突後,才能使用該地址。在檢測完成前,該地址被稱為“臨時地址”或“候選地址”(tentative address)。

使用鄰居發現過程來進行重複地址檢測。

主機傳送NS,其中源地址為“未指定地址”(unspecified address),即全0的IPv6地址“::”。目的地址為使用臨時地址生成的請求節點多播地址。Target Address中包含該臨時地址。這種NS不攜帶源鏈路層地址選項(Source Link-layer Address)。

源地址使用“未指定地址”的原因是,此時介面還沒有地址,在重複地址檢查完成前,臨時地址不會被分配給介面。

不攜帶源鏈路層地址選項的原因是,若存在衝突,其它節點在回覆時,會將NA發往所有節點多播地址,不需要此資訊。

主機預期此NS訊息不會收到回覆。若收到回覆,則表面存在地址衝突。主機需要重新生成介面ID,進而生成新的IPv6地址,再次執行重複地址檢測過程。

路由器使用單播還是多播傳送RA?

路由器在收到RS後,會回覆RA。路由器根據自身情況決定使用單播還是多播進行回覆。

路由器本身會週期性的傳送多播RA。鄰居發現協議對RA做了限速。路由器在收到RS後,會計算一個時延。若下一個週期性RA的傳送時間比當前時間加上時延更早,則按計劃傳送週期性的多播RA。否則,傳送單播RA給主機。

主機獲取DNS伺服器資訊的方法有哪些?

目前主機有3中方式獲取DNS伺服器資訊:

  1. 使用DHCPv6從伺服器獲取;
  2. 從RA中獲取,使用Recursive DNS Server選項;
  3. 使用知名任播地址,在系統內預設定;

這3種方式中,最常見的是第一種。

第二種方式出現的較晚,最開始在RFC5006中定義,後被RFC6106替代,最新的標準是RFC8106。這種方式使用的也不多。

第三種方式用到的最少。

如何撤銷或修改字首?

家庭寬頻中,路由器或光貓在WAN側到BRAS進行PPPOE撥號,透過IPCP獲取IPv4地址,透過IPV6CP協商IPv6介面ID。後續透過RS/RA流程獲取字首資訊,生成WAN口的全域性IPv6地址。然後透過DHCPv6從BRAS獲取IA_PD,即代理字首。此代理字首長度一般小於或等於64位。

路由器或光貓隨後從代理字首中劃分出一個64位字首,用於下掛終端的SLAAC配置。

在光貓WAN側重播號導致獲取的IA_PD字首發生變化,或者WAN側撥號失敗等情況發生時,需要撤銷之前宣告的字首。

路由器傳送RA訊息,將字首的Valid Lifetime設定為0。主機收到此類RA之後,會立即將字首列表中對應的條目設定為超時(參考RFC4861第6.3.5節)。

在路由器斷電重啟的場景下,若重啟前後從WAN側獲取的IA_PD不一致,路由器無法將重啟前的字首宣告為無效以撤銷。這會造成終端上有多個IP地址。若終端在發起IPv6連線時選擇了錯誤的地址,則可能造成通訊失敗。

這裡的超時是將字首列表中的條目設定為超時,而字首列表的用途是進行同一鏈路(on-link)判定,即在傳送報文時,根據目的IPv6地址和字首列表中的資訊來決定將報文直接發往目標主機還是閘道器。

在RFC4862(IPv6無狀態地址自動配置)第5.5.3節(處理路由器宣告)第e)中,有如下規定:

針對地址的有效生命週期具體採取的行動取決於接收的宣告中的有效生命週期和之前自動配置的地址的有效生命週期的剩餘時間。在下文的討論中,我們將剩餘的時間稱為“RemainingLifetime”:

  1. 若接收的有效生命週期長於2小時或比RemainingLifetime長,則將地址的有效生命週期設定為被宣告的有效生命週期。
  2. 若RemainingLifetime小於或等於2小時,則忽略字首資訊選項中的有效生命週期,除非包含字首資訊選項的路由器宣告訊息已被認證(例如,透過RFC3971中說明的安全的鄰居發現)。若路由器宣告訊息被認證透過,則地址的有效週期應該被設定為接收的字首資訊選項中攜帶的有效生命週期。
  3. 其它情況下,將地址的有效週期重置為2小時。

這些規則的初衷是為了避免拒絕服務攻擊。根據這些規則,如果想撤銷某個字首,即使在RA報文中包含了有效生命週期為0的字首資訊選項,主機也會將地址保留至少2個小時。

為什麼經常看到Windows電腦上有很多IPv6地址?

這主要有以下幾個原因:

  1. Windows系統針對同一個字首,至少生成2個地址,其中一個被稱為“穩定地址”,用於從外部訪問主機;一個被稱為“臨時地址”,用於本機發起到外部的連線。
  2. Windows預設啟用了隱私擴充套件,生成的臨時地址會有一個較短的生命週期。在臨時地址的生命週期到期後,地址會變為廢止狀態,並生成新的臨時地址。但此時若有應用程式仍在使用被廢止的地址,則該地址不會被刪除。

上述兩個原因導致啟用IPv6的Windows系統在執行一段時間後,會看到有很多IPv6地址。

Windows上禁用隱私擴充套件(即不自動生成臨時地址)的方法:

使用管理員身份開啟cmd命令列,執行下列命令

netsh interface ipv6 set privacy state=disabled

下圖是禁用之前的效果,可以看到針對每個字首,都至少有1個臨時地址。

IPv6無狀態地址自動配置(SLAAC)-常見問題

禁用過程(執行此命令後可能需要禁用再啟用網路卡):

IPv6無狀態地址自動配置(SLAAC)-常見問題

下圖是禁用之後的效果,可以看到,系統沒有再生成IPv6臨時地址:

IPv6無狀態地址自動配置(SLAAC)-常見問題

為什麼windows電腦上IPv6地址的後64位介面ID和MAC沒有關係?

在使用SLAAC時,IPv6地址的後64位被稱為介面識別符號,也被簡稱為IID(Interface Identifier),由主機自己生成。

標準文件中介紹的生成介面ID的演算法一般是根據48位的MAC地址來生成IEEE EUI-64標識。Windows系統出於安全考慮等因素,使用了隨機的介面ID。這同時也是後續標準文件中推薦的做法。

生成介面識別符號的方式有很多,包括但不限於以下的方式:

  • 基於IEEE識別符號的IID,這是在RFC4291中定義的;
  • 靜態/手工配置IID,即由使用者自己指定;
  • 固定的,語義不透明的IID,這是Windows系統使用的方式,最新標準是RFC8981;
  • 加密生成的IID,也被稱為CGA;
  • 穩定的,語義不透明的IID,這種方法由RFC7217指定;

...

在Windows下可以使用下列命令來關閉隨機生成介面ID:

Netsh interface ipv6 set global randomizeidentifiers=disabled

關閉之後的效果如下:

可以看到,IPv6地址中的IID部分是由48位MAC地址生成的。

IPv6無狀態地址自動配置(SLAAC)-常見問題

相關文章