深刻理解iptables防火牆

本文部份內容節選自: netfilter/iptables 簡介 - IBM developerWorks

0x00 Linux 安全性和 netfilter/iptables

  • Linux 因其健壯性、可靠性、靈活性以及好象無限範圍的可定製性而在 IT 業界變得很是受歡迎。Linux 具備許多內置的能力, 使開發人員能夠根據本身的須要定製其工具、行爲和外觀,而無需昂貴的第三方工具。 若是 Linux 系統鏈接到因特網或 LAN、服務器或鏈接 LAN 和因特網的代理服務器, 所要用到的一種內置能力就是針對網絡上 Linux 系統的防火牆配置。 能夠在 netfilter/iptables IP 信息包過濾系統(它集成在 2.4.x 版本的 Linux 內核中)的幫助下運用這種能力。
  • 在如 ipfwadm和 ipchains 這樣的 Linux 信息包過濾解決方案中,netfilter/iptables IP 信息包過濾系統是最新的解決方案, 並且也是第一個集成到 Linux 內核的解決方案。 對於 Linux 系統管理員、網絡管理員以及家庭用戶(他們 想要根據本身特定的需求來配置防火牆、在防火牆解決方案上節省費用和對 IP 信息包過濾具備徹底控制權)來講,netfilter/iptables 系統十分理想。

0x01 理解防火牆配置和信息包過濾

  • 對於鏈接到網絡上的 Linux 系統來講,防火牆是必不可少的防護機制, 它只容許合法的網絡流量進出系統,而禁止其它任何網絡流量。爲了肯定網絡流量是否合法, 防火牆依靠它所包含的由網絡或系統管理員預約義的一組 規則。 這些規則告訴防火牆某個流量是否合法以及對於來自某個源、至某個目的地或具備某種協議類型的網絡流量要作些什麼。 術語「配置防火牆」是指添加、修改和除去這些規則。稍後,我將詳細討論這些規則。
  • 網絡流量由 IP 信息包(或,簡稱 信息包)— 以流的形式從源系統傳輸到目的地系統的一些小塊數據 — 組成。 這些信息包有頭,即在每一個包前面所附帶的一些數據位,它們包含有關信息包的源、目的地和協議類型的信息。 防火牆根據一組規則檢查這些頭,以肯定接受哪一個信息包以及拒絕哪一個信息包。咱們將該過程稱爲信息包過濾。

0x02 爲何要配置本身的防火牆?

  • 出於各類因素和緣由,須要根據特定需求來配置防火牆。 或許,最重要的緣由是安全性。
  • 管理員可能想讓他們的防火牆可以阻止未經受權的源訪問其 Linux 系統,例如經過 Telnet。 他們可能還想限制進出其系統的網絡流量,以便只有來自可信源的流量才能夠進入其系統,以及只有受權的流量才能夠出去。 家庭用戶可能經過容許全部的出站信息包均可以經過,將防火牆配置成較低的安全性級別。
  • 另外一個背後的緣由是,經過阻塞來自相似廣告站點之類的源的多餘流量,能夠節省帶寬。

於是,能夠定製防火牆配置來知足任何特定需求和任何安全性級別需求。 這就是 netfilter/iptables 系統的用武之處。html

0x03 netfilter/iptables 系統是如何工做的?

  • netfilter/iptables IP 信息包過濾系統是一種功能強大的工具, 可用於添加、編輯和除去規則,這些規則是在作信息包過濾決定時,防火牆所遵循和組成的規則。這些規則存儲在專用的信息包過濾表中, 而這些表集成在 Linux 內核中。 在信息包過濾表中,規則被分組放在咱們所謂的鏈(chain)中。我立刻會詳細討論這些規則以及如何創建這些規則並將它們分組在鏈中。
  • 雖然 netfilter/iptables IP 信息包過濾系統被稱爲單個實體,但它實際上由兩個組件 netfilter和 iptables 組成。
  • netfilter 組件也稱爲 內核空間(kernelspace),是內核的一部分,由一些信息包過濾表組成, 這些表包含內核用來控制信息包過濾處理的規則集。
  • iptables 組件是一種工具,也稱爲 用戶空間(userspace),它使插入、修改和除去信息包過濾表中的規則變得容易。 除非您正在使用 Red Hat Linux 7.1 或更高版本,不然須要從 netfilter.org 下載該工具並安裝使用它。
  • 經過使用用戶空間,能夠構建本身的定製規則,這些規則存儲在內核空間的信息包過濾表中。 這些規則具備 目標,它們告訴內核對來自某些源、前往某些目的地或具備某些協議類型的信息包作些什麼。 若是某個信息包與規則匹配,那麼使用目標 ACCEPT 容許該信息包經過。還可使用目標 DROPREJECT 來阻塞並殺死信息包。對於可對信息包執行的其它操做,還有許多其它目標。
  • 根據規則所處理的信息包的類型,能夠將規則分組在鏈中。處理入站信息包的規則被添加到 INPUT 鏈中。處理出站信息包的規則被添加到 OUTPUT 鏈中。處理正在轉發的信息包的規則被添加到 FORWARD 鏈中。這三個鏈是基本信息包過濾表中內置的缺省主鏈。 另外,還有其它許多可用的鏈的類型(如 PREROUTINGPOSTROUTING ), 以及提供用戶定義的鏈。每一個鏈均可以有一個策略, 它定義「缺省目標」,也就是要執行的缺省操做,當信息包與鏈中的任何規則都不匹配時,執行此操做。
  • 創建規則並將鏈放在適當的位置以後,就能夠開始進行真正的信息包過濾工做了。 這時內核空間從用戶空間接管工做。當信息包到達防火牆時,內核先檢查信息包的頭信息,尤爲是信息包的目的地。 咱們將這個過程稱爲 路由。
  • 若是信息包源自外界並前往系統,並且防火牆是打開的,那麼內核將它傳遞到內核空間信息包過濾表的 INPUT 鏈。若是信息包源自系統內部或系統所鏈接的內部網上的其它源,而且此信息包要前往另外一個外部系統, 那麼信息包被傳遞到 OUTPUT 鏈。相似的,源自外部系統並前往外部系統的信息包被傳遞到 FORWARD 鏈。
  • 接下來,將信息包的頭信息與它所傳遞到的鏈中的每條規則進行比較,看它是否與某條規則徹底匹配。 若是信息包與某條規則匹配,那麼內核就對該信息包執行由該規則的目標指定的操做。 可是,若是信息包與這條規則不匹配,那麼它將與鏈中的下一條規則進行比較。 最後,若是信息包與鏈中的任何規則都不匹配,那麼內核將參考該鏈的策略來決定如何處理該信息包。 理想的策略應該告訴內核 DROP 該信息包。

0x04 創建規則和鏈

  • 經過向防火牆提供有關對來自某個源、到某個目的地或具備特定協議類型的信息包要作些什麼的指令,規則控制信息包的過濾。 經過使用 netfilter/iptables 系統提供的特殊命令 iptables ,創建這些規則,並將其添加到內核空間的特定信息包過濾表內的鏈中。關於添加/除去/編輯規則的命令的通常語法以下:
iptables [-t table] command [match] [target]

0x05 表(table)

  • [-t table] 選項容許使用標準表以外的任何表。表是包含僅處理特定類型信息包的規則和鏈的信息包過濾表。 有三種可用的表選項: filternatmangle 。該選項不是必需的,若是未指定, 則 filter 用做缺省表。
  • filter 表用於通常的信息包過濾,它包含 INPUTOUTPUTFORWARD 鏈。nat 表用於要轉發的信息包,它包含 PREROUTINGOUTPUTPOSTROUTING 鏈。 若是信息包及其頭內進行了任何更改,則使用 mangle 表。 該表包含一些規則來標記用於高級路由的信息包,該表包含 PREROUTINGOUTPUT 鏈。
  • 注:PREROUTING 鏈由指定信息包一到達防火牆就改變它們的規則所組成,而 POSTROUTING 鏈由指定正當信息包打算離開防火牆時改變它們的規則所組成。

0x06 命令(command)

  • 上面這條命令中具備強制性的 command 部分是 iptables 命令的最重要部分。 它告訴 iptables 命令要作什麼,例如,插入規則、將規則添加到鏈的末尾或刪除規則。 如下是最經常使用的一些命令:
  • -A--append : 該命令將一條規則附加到鏈的末尾。
  • 示例:
iptables -A INPUT -s 205.168.0.1 -j ACCEPT
  • 該示例命令將一條規則附加到 INPUT 鏈的末尾,肯定來自源地址 205.168.0.1 的信息包能夠 ACCEPT 。
  • -D--delete : 經過用 -D 指定要匹配的規則或者指定規則在鏈中的位置編號,該命令從鏈中刪除該規則。 下面的示例顯示了這兩種方法。
  • 示例:
iptables -D INPUT --dport 80 -j DROP 
iptables -D OUTPUT 3
  • 第一條命令從 INPUT 鏈刪除規則,它指定 DROP 前往端口 80 的信息包。第二條命令只是從 OUTPUT 鏈刪除編號爲 3 的規則。
  • -P--policy : 該命令設置鏈的缺省目標,即策略。 全部與鏈中任何規則都不匹配的信息包都將被強制使用此鏈的策略。
  • 示例:
iptables -P INPUT DROP
  • 該命令將 INPUT 鏈的缺省目標指定爲 DROP 。這意味着,將丟棄全部與 INPUT 鏈中任何規則都不匹配的信息包。
  • -N--new-chain : 用命令中所指定的名稱建立一個新鏈。
  • 示例:
iptables -N allowed-chain
  • -F--flush : 若是指定鏈名,該命令刪除鏈中的全部規則, 若是未指定鏈名,該命令刪除全部鏈中的全部規則。此參數用於快速清除。
  • 示例:
iptables -F FORWARD 
iptables -F
  • -X--delete-chain : 若是指定鏈名,該命令刪除這條自定義的鏈, 若是未指定鏈名,該命令刪除全部自定義的鏈。此參數用於快速清除全部自定義的鏈,固然,默認的鏈沒法刪除。
  • 示例:
iptables -X MY_OWN_INPUT 
iptables -X
  • -L--list : 列出指定鏈中的全部規則。
  • 示例:
iptables -L allowed-chain

0x07 匹配(match)

  • iptables 命令的可選 match 部分指定信息包與規則匹配所應具備的特徵(如源和目的地地址、協議等)。 匹配分爲兩大類: 通用匹配和特定於協議的匹配。這裏,我將研究可用於採用任何協議的信息包的通用匹配。 下面是一些重要的且經常使用的通用匹配及其示例和說明:
  • -p--protocol : 該通用協議匹配用於檢查某些特定協議。 協議示例有 TCPUDPICMP 、用逗號分隔的任何這三種協議的組合列表以及 ALL (用於全部協議)。 ALL 是缺省匹配。可使用 ! 符號,它表示不與該項匹配。
  • 示例:
iptables -A INPUT -p TCP, UDP 
iptables -A INPUT -p ! ICMP
  • 在上述示例中,這兩條命令都執行同一任務 — 它們指定全部 TCPUDP 信息包都將與該規則匹配。 經過指定 ! ICMP ,咱們打算容許全部其它協議(在這種狀況下是 TCPUDP ), 而將 ICMP 排除在外。
  • -s--source : 該源匹配用於根據信息包的源 IP 地址來與它們匹配。該匹配還容許對某一範圍內的 IP 地址進行匹配,可使用 ! 符號,表示不與該項匹配。缺省源匹配與全部 IP 地址匹配。
  • 示例:
iptables -A OUTPUT -s 192.168.1.1 
iptables -A OUTPUT -s 192.168.0.0/24 
iptables -A OUTPUT -s ! 203.16.1.89
  • 第二條命令指定該規則與全部來自 192.168.0.0192.168.0.24 的 IP 地址範圍的信息包匹配。第三條命令指定該規則將與 除來自源地址 203.16.1.89 外的任何信息包匹配。
  • -d--destination : 該目的地匹配用於根據信息包的目的地 IP 地址來與它們匹配。 該匹配還容許對某一範圍內 IP 地址進行匹配,可使用 ! 符號,表示不與該項匹配。
  • 示例:
iptables -A INPUT -d 192.168.1.1 
iptables -A INPUT -d 192.168.0.0/24 
iptables -A OUTPUT -d ! 203.16.1.89

0x08 目標(target)

  • 咱們已經知道,目標是由規則指定的操做,對與那些規則匹配的信息包執行這些操做。 除了容許用戶定義的目標以外,還有許多可用的目標選項。下面是經常使用的一些目標及其示例和說明:
  • ACCEPT : 當信息包與具備 ACCEPT 目標的規則徹底匹配時, 會被接受(容許它前往目的地),而且它將中止遍歷鏈(雖然該信息包可能遍歷另外一個表中的其它鏈,而且有可能在那裏被丟棄)。 該目標被指定爲 -j ACCEPT
  • DROP : 當信息包與具備 DROP 目標的規則徹底匹配時,會阻塞該信息包,而且不對它作進一步處理。 該目標被指定爲 -j DROP
  • REJECT : 該目標的工做方式與 DROP 目標相同,但它比 DROP 好。和 DROP 不一樣, REJECT 不會在服務器和客戶機上留下死套接字。 另外, REJECT 將錯誤消息發回給信息包的發送方。該目標被指定爲 -j REJECT
  • 示例:
iptables -A FORWARD -p TCP --dport 22 -j REJECT
  • RETURN : 在規則中設置的 RETURN 目標讓與該規則匹配的信息包中止遍歷包含該規則的鏈。 若是鏈是如 INPUT 之類的主鏈,則使用該鏈的缺省策略處理信息包。 它被指定爲 -jump RETURN 。示例:
iptables -A FORWARD -d 203.16.1.89 -jump RETURN
  • 還有許多用於創建高級規則的其它目標,如 LOGREDIRECTMARKMIRRORMASQUERADE 等。

0x09 保存規則

  • 如今,您已經學習瞭如何創建基本的規則和鏈以及如何從信息包過濾表中添加或刪除它們。 可是,您應該記住:用上述方法所創建的規則會被保存到內核中,當從新引導系統時,會丟失這些規則。 因此,若是您將沒有錯誤的且有效的規則集添加到信息包過濾表,同時但願在從新引導以後再次使用這些規則, 那麼必須將該規則集保存在文件中。可使用 iptables-save命令來作到這一點:
iptables-save > iptables-script
  • 如今,信息包過濾表中的全部規則都被保存在文件 iptables-script 中。不管什麼時候再次引導系統, 均可以使用 iptables-restore 命令將規則集從該腳本文件恢復到信息包過濾表,以下所示:
iptables-restore iptables-script
  • 若是您願意在每次引導系統時自動恢復該規則集,則能夠將上面指定的這條命令放到任何一個初始化 shell 腳本中。

0x0A 僅使用包過濾的困境

  • 在FTP服務中,有主動方式和被動方式之分。其中主動模式比較簡單,在主動方式中,FTP使用21和20端口,其中21端口用於傳輸控制指令,而20端口用於傳輸數據,主動方式全部報文都須要在20端口排隊發送或者接收,這樣就限制了服務器的併發性能;而被動方式中,FTP服務器會經過PASV命令通告客戶端開放的端口(通常是一個大端口號),而後客戶端就來鏈接。
  • 這樣一來就出現了一個問題,由於通常狀況下iptables是針對端口進行的防火牆包過濾。若是想使用FTP的被動方式,服務器就須要開放全部1024以上端口,不然客戶端的鏈接會被DROP掉,這樣就會變得不安全。可是若是不使用被動方式的話,主動方式的傳輸速率實在是太慢了。這類問題是iptables包過濾沒法解決的問題。
  • 舉個例子,咱們首先將iptables在INPUT鏈和OUTPUT鏈的默認策略都設置爲DROP:
iptables -P INPUT DROP
iptables -P OUTPUT DROP
  • 而後咱們開放FTP服務器的21和20端口:
iptables -A INPUT -p tcp --dport 21 -j ACCEPT
iptables -A INPUT -p tcp --dport 20 -j ACCEPT
iptables -A OUTPUT -p tcp --sport 21 -j ACCEPT
iptables -A OUTPUT -p tcp --sport 20 -j ACCEPT
  • 這樣一來,就可使用FTP的主動方式來傳輸數據,咱們使用FileZilla來鏈接這個FTP服務器(位於10.128.0.1):
狀態:     正在鏈接 10.128.0.1:21...
狀態:     鏈接創建,等待歡迎消息...
狀態:     不安全的服務器,不支持 FTP over TLS。
狀態:     服務器不支持非 ASCII 字符。
狀態:     已登陸
狀態:     開始上傳 /Users/xiaolulwr/Documents/CAUC-Tec-Markdown/Linux/深刻理解iptables防火牆.md
狀態:     文件傳輸成功,傳輸了 16,532 字節 (用時1 秒)
狀態:     讀取「/root」的目錄列表...
狀態:     計算服務器時差...
狀態:     列出「/root」的目錄成功
  • 可是一旦咱們切換到被動方式,就沒法進行數據傳輸:
狀態:     正在鏈接 10.128.0.1:21...
狀態:     鏈接創建,等待歡迎消息...
狀態:     不安全的服務器,不支持 FTP over TLS。
狀態:     服務器不支持非 ASCII 字符。
狀態:     已登陸
狀態:     讀取目錄列表...
命令:     PWD
響應:     257 "/root"
命令:     TYPE I
響應:     200 Switching to Binary mode.
命令:     PASV
響應:     227 Entering Passive Mode (10,128,0,1,230,163)
命令:     LIST
錯誤:     目錄列表被用戶終止
  • 當咱們使用PASV嘗試切換到被動模式以後,切換是能夠成功的,可是切換以後再進行操做就沒法成功了,緣由也很好理解,由於除了關於20和21端口以外的報文都被DROP了。

0x0B 狀態檢查

  • 爲了解決上面的狀況,解決方式就是使用iptables的狀態檢查功能。
  • 狀態檢查功能,是指iptables除了能夠按照IP地址、端口號、協議類型等條件對報文進行過濾以外,還具備必定的對報文的傳輸狀態進行檢查的功能,也就是說,iptables能夠識別哪些報文屬於新產生的鏈接,哪些報文屬於伴隨鏈接。在FTP的被動模式中,PASV協商以後,FTP服務器將經過一個大的隨機端口和客戶端通訊,這些報文就是FTP控制鏈接的伴隨鏈接的報文。這些報文不是無緣無故產生的,若是沒有以前的FTP控制鏈接,就不會產生這些鏈接和報文。若是黑客想直接鏈接到大的端口上的話,這些鏈接就屬於新鏈接。這樣一來,就沒必要開放全部大於1024的端口,同時也能夠容許FTP的被動方式了。
  • 咱們在上述配置規則以外,再配置下面的規則:
iptables -A INPUT -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT
  • 上面規則的意思是,在iptables的INPUTOUTPUT鏈上,容許ESTABLISHEDRELATED狀態的TCP報文,那麼何爲鏈接狀態呢?下面介紹四種鏈接的狀態:linux

    • ESTABLISHED:第一個成功穿越防火牆的報文以後全部的報文;
    • NEW:一個鏈接的第一個報文,例如TCP鏈接中的SYN報文;
    • RELATED:伴隨鏈接的報文,即某個已經處於ESTABLISHED的鏈接所產生的報文,這些報文不屬於第一條鏈接,可是的確是由第一條鏈接產生的;
    • INVALID:沒法判斷狀態的報文。
  • 固然值得注意的是,iptables的這種狀態檢查不是十分智能的,它只能識別到運輸層的伴隨鏈接,也就是說,對於FTP的協議伴隨鏈接,這種方式並不能很好的進行檢查。
  • 在配置以後,就能夠正常使用被動方式了:
狀態:     正在鏈接 10.128.0.1:21...
狀態:     鏈接創建,等待歡迎消息...
狀態:     不安全的服務器,不支持 FTP over TLS。
狀態:     服務器不支持非 ASCII 字符。
狀態:     已登陸
狀態:     開始上傳 /Users/xiaolulwr/Documents/CAUC-Personal/我的博客/ssl.txt
狀態:     文件傳輸成功,傳輸了 3,550 字節 (用時1 秒)
狀態:     讀取「/root」的目錄列表...
狀態:     列出「/root」的目錄成功
狀態:     開始下載 /root/ssl.txt
狀態:     文件傳輸成功,傳輸了 3,550 字節 (用時1 秒)
狀態:     已從服務器斷開

0x0C 高級狀態檢查

0x0D 網絡地址轉換(NAT)

  • 網絡地址轉換(NAT)能夠解決IPv4地址不足的問題,使用NAT以後,局域網能夠對廣域網隱藏內部的細節,讓整個局域網在廣域網上只表現爲一個IP地址,這項技術普遍應用於企業網絡、校園網絡以及運營商的網絡,由於並非全部用戶都須要一個廣域網的地址,他們只須要一個私有網絡的地址就能夠了,雖然這個地址不能直接在廣域網上使用,可是經過啓用了NAT的路由器,這些擁有私有網絡地址的設備也能夠訪問廣域網上的資源。固然,隨着IPv6的普及,NAT的使用將會逐漸減小。
  • iptables也支持NAT功能,如前所述,iptable上中包含一個NAT表,其中有兩條缺省的鏈,也就是PREROUTINGPOSTROUTING 鏈,在這兩條鏈上配置規則能夠實現NAT功能。
  • 在配置NAT以前,首先回顧一下NAT的兩種形式:shell

    • 源地址轉換(SNAT):適用於由局域網中的主機發起鏈接的狀況。報文在通過NAT路由器時,將IP報文中的源IP地址轉換爲一個有效的廣域網地址;在服務器給一個在私有網絡中的主機返回響應報文時,目的IP地址就是這個局域網對外的廣域網地址。報文到達NAT路由器的時候,路由器要將該報文分發給對應的主機,將IP報文的目的IP地址轉換爲私有網絡地址;
    • 目的地址轉換(DNAT):又稱爲「端口轉發」,適用於由廣域網上的主機發起鏈接的狀況。當廣域網的主機訪問NAT路由器的廣域網端口時,能夠將NAT路由器的廣域網的端口映射到局域網內的某個IP地址的某個端口,這樣就能夠實現廣域網主機訪問局域網內的資源。
  • 這裏須要注意一點就是,SNAT和DNAT的「源」和「目的」指的並非「源地址轉換」和「目的地址轉換」,而是指的發起鏈接的過程當中的那個轉換,只考慮了請求包。其實能夠簡單的理解爲SNAT就是局域網主機發起鏈接,DNAT就是廣域網主機發起鏈接,要知道任何一個鏈接都是雙向傳輸數據,因此在配置防火牆的時候要特別注意這一點。
  • 在iptables上配置NAT時,也能夠配置SNAT和DNAT,咱們的實驗環境有三臺主機,它們的基本網絡狀況以下(注意;這裏的172.20.10.0網絡仍然是局域網,只是模擬了廣域網而已):
主機(做爲廣域網服務器)
接口名稱:wlan
IP地址:172.20.10.4
子網掩碼:255.255.255.240
默認網關:172.20.10.1


虛擬機A(做爲NAT路由器)
接口名稱:ens39(廣域網接口)
IP地址:172.20.10.3
子網掩碼:255.255.255.240
默認網關:172.20.10.1

接口名稱:ens38(局域網接口)
IP地址:192.168.1.1
子網掩碼:255.255.255.0
配置:
ifconfig ens38 192.168.1.1 netmask 255.255.255.0


虛擬機B(做爲局域網主機)
接口名稱:eth1
IP地址:192.168.1.100
子網掩碼:255.255.255.0
默認網關:192.168.1.1
配置:
ifconfig eth1 192.168.1.100 netmask 255.255.255.0
route add default gw 192.168.1.1
  • 首先啓用虛擬機A的路由轉發功能,編輯/etc/sysctl.conf文件
vi /etc/sysctl.conf
  • 新增下面的條目:
net.ipv4.ip_forward=1
  • 使上面的更改當即生效
sysctl -p
  • 如今咱們在虛擬機A中配置iptables的NAT表,使虛擬機B能夠經過虛擬機A鏈接到主機的網絡。
# 適用於廣域網爲固定IP地址的狀況,本例是這種狀況
iptables -t nat -A POSTROUTING -o ens38 -s 192.168.1.0/24 -j SNAT --to-source 172.20.10.3
# 適用於廣域網爲動態分配IP地址的狀況,典型例子是PPPoE
iptables -t nat -A POSTROUTING –o ens38 –s 192.168.1.0/24 –j MASQUERADE
  • 命令的含義就是在路由操做以後,將從ens38接口上的192.168.1.0/24網絡上的報文的源IP地址,轉換爲廣域網地址172.20.10.3(或者經過PPPoE獲得的動態廣域網地址)併發送出去。這樣一來,在局域網中的虛擬機2就能夠訪問廣域網上的的資源了。
相關文章
相關標籤/搜索