Netfilter源代碼分析詳解_第1頁
Netfilter源代碼分析詳解_第2頁
Netfilter源代碼分析詳解_第3頁
Netfilter源代碼分析詳解_第4頁
Netfilter源代碼分析詳解_第5頁
已閱讀5頁,還剩33頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、一、概述1. Netfilter/IPTables 框架簡介Netfilter/IPTables 是繼 2.0.x 的 IPfwadm、2.2.x 的 IPchains 之后,新一代 的 Linux 防火墻機(jī)制。 Netfilter 采用模塊化設(shè)計(jì),具有良好的可擴(kuò)充性。其重要 工具模塊 IPTables 連接到 Netfilter 的架構(gòu)中,并允許使用者對(duì)數(shù)據(jù)報(bào)進(jìn)行過濾、 地址轉(zhuǎn)換、處理等操作。Netfilter 提供了一個(gè)框架,將對(duì)網(wǎng)絡(luò)代碼的直接干涉降到最低,并允許用 規(guī)定的接口將其他包處理代碼以模塊的形式添加到內(nèi)核中,具有極強(qiáng)的靈活性。主要源代碼文件 Linux 內(nèi)核版本: 2.4.21

2、Netfilter 主文件: net/core/netfilter.cNetfilter 主頭文件:include/linux/netfilter.h IPv4 相關(guān):c 文件: net/ipv4/netfilter/*.c頭文件: include/linux/netfilter_ipv4.hinclude/linux/netfilter_ipv4/*.h IPv4 協(xié)議棧主體的部分 c 文件,特別是與數(shù)據(jù)報(bào)傳送過程有關(guān)的部分:ip_input.c,ip_forward.c,ip_output.c,ip_fragment.c 等二、Netfilter/IPTablesIPv4 總體架構(gòu)Netf

3、ilter主要通過表、鏈實(shí)現(xiàn)規(guī)則,可以這么說,Netfilter是表的容器,表是鏈的容器,鏈?zhǔn)且?guī)則的容器,最終形成對(duì)數(shù)據(jù)報(bào)處理規(guī)則的實(shí)現(xiàn)。詳細(xì)地說, Netfilter/IPTables 的體系結(jié)構(gòu)可以分為三個(gè)大部分:Netfilter 的 HOOK 機(jī)制Netfilter 的通用框架不依賴于具體的協(xié)議,而是為每種網(wǎng)絡(luò)協(xié)議定義一套 HOOK 函數(shù)。這些 HOOK 函數(shù)在數(shù)據(jù)報(bào)經(jīng)過協(xié)議棧的幾個(gè)關(guān)鍵點(diǎn)時(shí)被調(diào)用,在 這幾個(gè)點(diǎn)中,協(xié)議棧將數(shù)據(jù)報(bào)及 HOOK 函數(shù)標(biāo)號(hào)作為參數(shù),傳遞給 Netfilter 框 架。對(duì)于它在網(wǎng)絡(luò)堆棧中增加的這些HOOK,內(nèi)核的任何模塊可以對(duì)每種協(xié)議 的一個(gè)或多個(gè) HOOK

4、進(jìn)行注冊(cè),實(shí)現(xiàn)掛接。這樣當(dāng)某個(gè)數(shù)據(jù)報(bào)被傳遞給 Netfilter 框架時(shí),內(nèi)核能檢測到是否有任何模塊對(duì)該協(xié)議和 HOOK 函數(shù)進(jìn)行了注冊(cè)。若 注冊(cè)了,則調(diào)用該模塊的注冊(cè)時(shí)使用的回調(diào)函數(shù),這樣這些模塊就有機(jī)會(huì)檢查、 修改、丟棄該數(shù)據(jù)報(bào)及指示 Netfilter 將該數(shù)據(jù)報(bào)傳入用戶空間的隊(duì)列。這樣, HOOK 提供了一種方便的機(jī)制:在數(shù)據(jù)報(bào)通過 Linux 內(nèi)核的不同 位置上截獲和操作處理數(shù)據(jù)報(bào)。IPTables 基礎(chǔ)模塊IPTables 基礎(chǔ)模塊實(shí)現(xiàn)了三個(gè)表來篩選各種數(shù)據(jù)報(bào),具體地講, Linux2.4 內(nèi)核提供的這三種數(shù)據(jù)報(bào)的處理功能是相互間獨(dú)立的模塊,都基于 Netfilter 的 HOOK

5、函數(shù)和各種表、鏈實(shí)現(xiàn)。這三個(gè)表包括:filter表,nat表以及mangle表。3. 具體功能模塊1.數(shù)據(jù)報(bào)過濾模塊連接跟蹤模塊(Conntrack)網(wǎng)絡(luò)地址轉(zhuǎn)換模塊(NAT)數(shù)據(jù)報(bào)修改模塊( mangle)其它高級(jí)功能模塊于是,Netfilter/IPTables總體架構(gòu)如圖 HYPERLINK /photo/24896_061206192251.jpg /photo/24896_061206192251.jpg 所示三、HOOK的實(shí)現(xiàn)1. Netfilter-IPv4 中的 HOOKNetfilter 模塊需要使用 HOOK 來啟用函數(shù)的動(dòng)態(tài)鉤接,它在 IPv4 中定義了 五個(gè) HOOK

6、(位于文件 include/linux/netfilter_ipv4.h. Line 39),分別對(duì)應(yīng) 0-4 的 hooknum簡單地說,數(shù)據(jù)報(bào)經(jīng)過各個(gè) HOOK 的流程如下:數(shù)據(jù)報(bào)從進(jìn)入系統(tǒng),進(jìn)行 IP 校驗(yàn)以后,首先經(jīng)過第一個(gè) HOOK 函數(shù) NF_IP_PRE_ROUTING 進(jìn)行處理;然后就進(jìn)入路由代碼,其決定該數(shù)據(jù)報(bào)是需 要轉(zhuǎn)發(fā)還是發(fā)給本機(jī)的;若該數(shù)據(jù)報(bào)是發(fā)被本機(jī)的,則該數(shù)據(jù)經(jīng)過 HOOK 函數(shù) NF_IP_LOCAL_IN 處理以后然后傳遞給上層協(xié)議;若該數(shù)據(jù)報(bào)應(yīng)該被轉(zhuǎn)發(fā)則它 被 NF_IP_FORWARD 處理;經(jīng)過轉(zhuǎn)發(fā)的數(shù)據(jù)報(bào)經(jīng)過最后一個(gè) HOOK 函數(shù) NF_IP_POST

7、_ROUTING 處理以后,再傳輸?shù)骄W(wǎng)絡(luò)上。本地產(chǎn)生的數(shù)據(jù)經(jīng)過 HOOK 函數(shù) NF_IP_LOCAL_OUT 處理后,進(jìn)行路由選擇處理,然后經(jīng)過 NF_IP_POST_ROUTING 處理后發(fā)送出去??傊@五個(gè) HOOK 所組成的 Netfilter-IPv4 數(shù)據(jù)報(bào)篩選體系如圖 HYPERLINK /photo/24896_061206192311.jpg%ef%bc%9a /photo/24896_061206192311.jpg: (注:下面所 說Netfilter/IPTables均基于IPv4,不再贅述)詳細(xì)地說,各個(gè) HOOK 及其在 IP 數(shù)據(jù)報(bào)傳遞中的具體位置如圖 HYPE

8、RLINK /photo/24896_061206192340.jpg /photo/24896_061206192340.jpg NF_IP_PRE_ROUTING (0)數(shù)據(jù)報(bào)在進(jìn)入路由代碼被處理之前,數(shù)據(jù)報(bào)在IP數(shù)據(jù)報(bào)接收函數(shù)ip_rcv() (位于net/ipv4/ip_input.c,Line379)的最后,也就是在傳入的數(shù)據(jù)報(bào)被處理之 前經(jīng)過這個(gè)HOOK。在ip_rcv()中掛接這個(gè)HOOK之前,進(jìn)行的是一些與類型、 長度、版本有關(guān)的檢查。經(jīng)過這個(gè)HOOK處理之后,數(shù)據(jù)報(bào)進(jìn)入ip_rcv_finish()(位于 net/ipv4/ip_input.c,Line306),進(jìn)行查路由表

9、的工作,并判斷該數(shù)據(jù)報(bào)是發(fā)給本 地機(jī)器還是進(jìn)行轉(zhuǎn)發(fā)。在這個(gè) HOOK 上主要是對(duì)數(shù)據(jù)報(bào)作報(bào)頭檢測處理,以捕獲異常情況。涉及功能(優(yōu)先級(jí)順序):Conntrack(-200)、mangle(-150)、DNAT(-IOO) NF_IP_LOCAL_IN (1)目的地為本地主機(jī)的數(shù)據(jù)報(bào)在 IP 數(shù)據(jù)報(bào)本地投遞函數(shù) ip_local_deliver() (位于 net/ipv4/ip_input.c,Line290)的最后經(jīng)過這個(gè) HOOK。經(jīng)過這個(gè)HOOK處理之后,數(shù)據(jù)報(bào)進(jìn)入ip_local_deliver_finish()(位于 net/ipv4/ip_input.c, Line219)這樣,I

10、PTables模塊就可以利用這個(gè)HOOK對(duì)應(yīng)的INPUT規(guī)則鏈表來 對(duì)數(shù)據(jù)報(bào)進(jìn)行規(guī)則匹配的篩選了。防火墻一般建立在這個(gè) HOOK 上。涉及功能:mangle(-150)、filter(O)、SNAT(IOO)、Conntrack(INT_MAX-l) NF_IP_FORWARD (2)目的地非本地主機(jī)的數(shù)據(jù)報(bào),包括被 NAT 修改過地址的數(shù)據(jù)報(bào),都要在 IP 數(shù)據(jù)報(bào)轉(zhuǎn)發(fā)函數(shù) ip_forward()(位于 net/ipv4/ip_forward.c, Line73 )的最后經(jīng) 過這個(gè) HOOK。經(jīng)過這個(gè)HOOK處理之后,數(shù)據(jù)報(bào)進(jìn)入ip_forward_finish()(位于 net/ipv4/

11、ip_forward.c, Line44)另外,在 net/ipv4/ipmr.c 中的 ipmr_queue_xmit()函數(shù)(Line1119)最后也 會(huì)經(jīng)過這個(gè)HOOK(ipmr為多播相關(guān),估計(jì)是在需要通過路由轉(zhuǎn)發(fā)多播數(shù)據(jù) 時(shí)的處理)這樣, IPTables 模塊就可以利用這個(gè) HOOK 對(duì)應(yīng)的 FORWARD 規(guī)則鏈 表來對(duì)數(shù)據(jù)報(bào)進(jìn)行規(guī)則匹配的篩選了。涉及功能: mangle(-150)、 filter(0) NF_IP_LOCAL_OUT (3)本地主機(jī)發(fā)出的數(shù)據(jù)報(bào)在 IP 數(shù)據(jù)報(bào)構(gòu)建/發(fā)送函數(shù) ip_queue_xmit() 位于 net/ipv4/ip_output.c, Lin

12、e339)、以及 ip_build_and_send_pkt()(位于 net/ipv4/ip_output.c, Line122)的最后經(jīng)過這個(gè)HOOK。(在數(shù)據(jù)報(bào)處理中,前 者最為常用,后者用于那些不傳輸有效數(shù)據(jù)的 SYN/ACK 包)經(jīng)過這個(gè)HOOK處理后,數(shù)據(jù)報(bào)進(jìn)入ip_queue_xmit2()(位于 net/ipv4/ip_output.c, Line281)另外,在 ip_build_xmit_slow()(位于 net/ipv4/ip_output.c,Line429 )和 ip_build_xmit()(位于 net/ipv4/ip_output.c,Line638)中用于進(jìn)

13、行錯(cuò)誤檢測;在 igmp_send_report()(位于 net/ipv4/igmp.c, Line195)的最后也經(jīng)過了這個(gè) HOOK, 進(jìn)行多播時(shí)相關(guān)的處理。這樣, IPTables 模塊就可以利用這個(gè) HOOK 對(duì)應(yīng)的 OUTPUT 規(guī)則鏈表 來對(duì)數(shù)據(jù)報(bào)進(jìn)行規(guī)則匹配的篩選了。涉及功能: Conntrack(-200)、 mangle(-150)、 DNAT(-100)、 filter(0) NF_IP_POST_ROUTING (4)所有數(shù)據(jù)報(bào),包括源地址為本地主機(jī)和非本地主機(jī)的,在通過網(wǎng)絡(luò)設(shè)備 離開本地主機(jī)之前,在IP數(shù)據(jù)報(bào)發(fā)送函數(shù)ip_finish_output()(位于 net/

14、ipv4/ip_output.c, Linel84)的最后經(jīng)過這個(gè) HOOK。經(jīng)過這個(gè)HOOK處理后,數(shù)據(jù)報(bào)進(jìn)入ip_finish_output2()(位于 net/ipv4/ip_output.c, Line160)另外,在函數(shù) ip_mc_output()(位于 net/ipv4/ip_output.c, Line195)中在克隆新的網(wǎng)絡(luò)緩存skb時(shí),也經(jīng)過了這個(gè)HOOK 進(jìn)行處理。涉及功能:mangle(-150)、SNAT(100)、Conntrack(INT_MAX)其中,入口為 net_rx_action()(位于 net/core/dev.c,Line1602),作用是 將數(shù)據(jù)報(bào)

15、一個(gè)個(gè)地從 CPU 的輸入隊(duì)列中拿出,然后傳遞給協(xié)議處理例程。出口為 dev_queue_xmit()(位于 net/core/dev.c,Line1035),這個(gè)函數(shù)被 高層協(xié)議的實(shí)例使用,以數(shù)據(jù)結(jié)構(gòu) struct sk_buff *skb 的形式在網(wǎng)絡(luò)設(shè)備上發(fā)送 數(shù)據(jù)報(bào)。2. HOOK 的調(diào)用HOOK 的調(diào)用是通過宏 NF_HOOK 實(shí)現(xiàn)的,其定義位于 include/linux/Netfilter.h, Line122:#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) / (list_empty(&nf_hooks(pf)(hook)

16、 /(okfn)(skb) /: nf_hook_slow(pf), (hook), (skb), (indev), (outdev), (okfn)這里先調(diào)用 list_empty 函數(shù)檢查 HOOK 點(diǎn)存儲(chǔ)數(shù)組 nf_hooks 是否為空, 為空則表示沒有 HOOK 注冊(cè),則直接調(diào)用 okfn 繼續(xù)處理。如果不為空,則轉(zhuǎn)入 nf_hook_slow()函數(shù)。nf_hook_slow()函數(shù)(位于 net/core/netfilter.c,Line449)的工作主要是讀 nf_hook數(shù)組遍歷所有的nf_hook_ops結(jié)構(gòu),并調(diào)用nf_hookfn()處理各個(gè)數(shù)據(jù)報(bào)。即 HOOK 的調(diào)用過

17、程如圖 HYPERLINK /photo/24896_061206192356.jpg /photo/24896_061206192356.jpg 所示下面說明一下 NF_HOOK 的各個(gè)參數(shù):pf:協(xié)議族標(biāo)識(shí),相關(guān)的有效協(xié)議族列表位于include/linux/socket.h,Line 178。對(duì)于IPv4,應(yīng)該使用協(xié)議族PF_INET; hook : HOOK 標(biāo)識(shí),即前面所說 5 個(gè) HOOK 對(duì)應(yīng)的 hooknum ; skb:是含有需要被處理包的sk_buuff數(shù)據(jù)結(jié)構(gòu)的指針。sk_buff是Linux 網(wǎng)絡(luò)緩存,指那些 linux 內(nèi)核處理 IP 分組報(bào)文的緩存,即套接字緩沖區(qū)。

18、網(wǎng)卡收到IP分組報(bào)文后,將它們放入sk_buff,然后再傳送給網(wǎng)絡(luò)堆棧,網(wǎng)絡(luò)堆 棧幾乎一直要用到sk_buff。其定義在include/linux/skbuff.h, Line 129,下面列出 我認(rèn)為對(duì)分析有意義的部分成員:o struct sock *sk;:指向創(chuàng)建分組報(bào)文的socket;o struct timeval stamp;:分組報(bào)文到達(dá)系統(tǒng)的時(shí)間;o下面是二個(gè)union,存放的是各層中各種協(xié)議的報(bào)文頭指針:h對(duì)應(yīng)傳輸層的報(bào)頭nh對(duì)應(yīng)網(wǎng)絡(luò)層的報(bào)頭 mac對(duì)應(yīng)MAC層的報(bào)頭o unsigned int len;:套接字緩存所代表的報(bào)文長度,即從unsigned char *dat

19、a; 的位置算起的當(dāng)前有效報(bào)文長度。o unsigned char pkt_type,:表示報(bào)文的類型,具體類型定義在 include/linux/if_packet.h, Line24:#define PACKET_HOST 0 / 發(fā)送到本機(jī)的報(bào)文#define PACKET_BROADCAST 1 / 廣播報(bào)文#define PACKET_MULTICAST 2 / 多播報(bào)文#define PACKET_OTHERHOST 3 / 表示目的地非本機(jī)但被本機(jī) 接收的報(bào)文#define PACKET_OUTGOING 4 / 離開本機(jī)的報(bào)文/* These ones are invisibl

20、e by user level */#define PACKET_LOOPBACK 5 / 本機(jī)發(fā)給自己的報(bào)文#define PACKET_FASTROUTE 6 / 快速路由報(bào)文indev:輸入設(shè)備,收到數(shù)據(jù)報(bào)的網(wǎng)絡(luò)設(shè)備的net_device數(shù)據(jù)結(jié)構(gòu)指針,即 數(shù)據(jù)報(bào)到達(dá)的接口。o 用于 NF_IP_PRE_ROUTING 和 NF_IP_LOCAL_IN 兩個(gè) HOOKoutdev:輸出設(shè)備,數(shù)據(jù)報(bào)離開本地所要使用的網(wǎng)絡(luò)設(shè)備的net_device數(shù) 據(jù)結(jié)構(gòu)指針。o 用于 NF_IP_LOCAL_OUT 和 NF_IP_POST_ROUTING 兩個(gè) HOOK o 注意:在通常情況下,在一次

21、HOOK 調(diào)用中, indev 和 outdev 中只 有一個(gè)參數(shù)會(huì)被使用 okfn:下一步要處理的函數(shù)。即如果有HOOK函數(shù),則處理完所有的HOOK 函數(shù),且所有向該 HOOK 注冊(cè)過的篩選函數(shù)都返回 NF_ACCEPT 時(shí),調(diào) 用這個(gè)函數(shù)繼續(xù)處理;如果沒有注冊(cè)任何HOOK,則直接調(diào)用此函數(shù)。 其 5 個(gè)參數(shù)將由宏 NF_HOOK 傳入。3. HOOK 點(diǎn)的實(shí)現(xiàn)對(duì)應(yīng)于各個(gè)不同協(xié)議的不同 HOOK 點(diǎn)是由一個(gè)二維數(shù)組 nf_hooks 存儲(chǔ) 的(位于 net/core/netfilter.c, Line 47),具體的 HOOK 點(diǎn)則由數(shù)據(jù)結(jié)構(gòu) nf_hook_ops (位于 include/

22、linux/netfilter.h, Line 44)實(shí)現(xiàn)。如圖 HYPERLINK /photo/24896_061206192528.jpg /photo/24896_061206192528.jpg 所示:其中, nf_hook_ops 成員中:int priority; priority值越小,優(yōu)先級(jí)越高,相關(guān)優(yōu)先級(jí)在 include/linux/netfilter_ipv4.h, Line52 中枚舉定義:enum NF_IP_hook_priorities NF_IP_PRI_FIRST = INT_MIN,NF_IP_PRI_CONNTRACK= -200,NF_IP_PRI_M

23、ANGLE = -150,NF_IP_PRI_NAT_DST = -100,NF_IP_PRI_FILTER = 0,NF_IP_PRI_NAT_SRC = 100,NF_IP_PRI_LAST = INT_MAX,;nf_hookfn *hook; 為處理函數(shù)的指針,其函數(shù)指針類型定義位于 include/linux/netfilter.h,Line38,為:typedef unsigned int nf_hookfn(unsigned int hooknum,struct sk_buff *skb,const struct net_device *in,const struct net_d

24、evice *out, int (*okfn)(struct sk_buff *);這是 nf_hook_ops 中最關(guān)鍵的成員,其五個(gè)參數(shù)分別對(duì)應(yīng)前面所解釋的NF_HOOK中弟2到6個(gè)參數(shù)調(diào)用 HOOK 的包篩選函數(shù)必須返回特定的值,這些值以宏的形式定義于 頭文件 include/linux/netfilter.h 中(Linel5),分別為:NF_DROP(0):丟棄此數(shù)據(jù)報(bào),禁止包繼續(xù)傳遞,不進(jìn)入此后的處 理流程;NF_ACCEPT(1):接收此數(shù)據(jù)報(bào),允許包繼續(xù)傳遞,直至傳遞到鏈 表最后,而進(jìn)入okfn函數(shù);以上兩個(gè)返回值最為常見NF_STOLEN(2):數(shù)據(jù)報(bào)被篩選函數(shù)截獲,禁止包繼

25、續(xù)傳遞,但并 不釋放數(shù)據(jù)報(bào)的資源,這個(gè)數(shù)據(jù)報(bào)及其占有的sk_buff仍然有效(e.g. 將分片的數(shù)據(jù)報(bào)一一截獲,然后將其裝配起來再進(jìn)行其他處 理);NF_QUEQUE(3):將數(shù)據(jù)報(bào)加入用戶空間隊(duì)列,使用戶空間的程序 可以直接進(jìn)行處理; 在 nf_hook_slow()以及 nf_reinject()函數(shù)(位于 net/core/netfilter.c, Line449, Line505)中,當(dāng)由調(diào)用 nf_iterate() 函數(shù)(位于net/core/netfilter.c,Line339,作用為遍歷所有注 冊(cè)的HOOK函數(shù),并返回相應(yīng)的NF_XX值)而返回的verdict 值為NF_QU

26、EUE時(shí)(即當(dāng)前正在執(zhí)行的這個(gè)HOOK篩選函 數(shù)要求將數(shù)據(jù)報(bào)加入用戶空間隊(duì)列),會(huì)調(diào)用nf_queue()函 數(shù)(位于 net/core/netfilter.c, Line407)nf_queue()函數(shù)將這個(gè)數(shù)據(jù)報(bào)加入用戶空間隊(duì)列nf_info (位 于 include/linux/netfilter.h, Line77),并保存其設(shè)備信息以 備用NF_REPEAT(4):再次調(diào)用當(dāng)前這個(gè)HOOK的篩選函數(shù),進(jìn)行重 復(fù)處理。4. HOOK 的注冊(cè)和注銷HOOK的注冊(cè)和注銷分別是通過nf_register_hook()函數(shù)和 nf_unregister_hook()函數(shù)(分別位于 net/co

27、re/netfilter.c,Line60,76)實(shí)現(xiàn)的,其 參數(shù)均為一個(gè) nf_hook_ops 結(jié)構(gòu),二者的實(shí)現(xiàn)也非常簡單。nf_register_hook()的工作是首先遍歷nf_hools,由HOOK的優(yōu)先級(jí)確定 在HOOK鏈表中的位置,然后根據(jù)優(yōu)先級(jí)將該HOOK的nf_hook_ops加入鏈表;nf_unregister_hook()的工作更加簡單,其實(shí)就是將該HOOK的nf_hook_ops 從鏈表中刪除。IPTables 系統(tǒng)表規(guī)則系統(tǒng)IPTables 是基于 Netfilter 基本架構(gòu)實(shí)現(xiàn)的一個(gè)可擴(kuò)展的數(shù)據(jù)報(bào)高級(jí)管理系 統(tǒng),利用 table、chain、rule 三級(jí)來存儲(chǔ)數(shù)

28、據(jù)報(bào)的各種規(guī)則。系統(tǒng)預(yù)定義了三個(gè) table:filter:數(shù)據(jù)報(bào)過濾表(文件 net/ipv4/netfilter/iptable_filter.c)監(jiān)聽 NF_IP_LOCAL_IN、NF_IP_FORWARD 和 NF_IP_LOCAL_OUT 三個(gè) HOOK, 作用是在所有數(shù)據(jù)報(bào)傳遞的關(guān)鍵點(diǎn)上對(duì)其進(jìn)行過濾。nat :網(wǎng)絡(luò)地址轉(zhuǎn)換表監(jiān)聽 NF_IP_PRE_ROUTING、 NF_IP_POST_ROUTING 和 NF_IP_LOCAL_OUT 三個(gè)HOOK,作用是當(dāng)新連接的第一個(gè)數(shù)據(jù)報(bào)經(jīng)過時(shí),在nat表中決定對(duì)其的轉(zhuǎn) 換操作;而后面的其它數(shù)據(jù)報(bào)都將根據(jù)第一個(gè)數(shù)據(jù)報(bào)的結(jié)果進(jìn)行相同的轉(zhuǎn)換

29、處理mangle:數(shù)據(jù)報(bào)修改表(位于 net/ipv4/netfilter/iptable_mangle.c)監(jiān)聽 NF_IP_PRE_ROUTING 和 NF_IP_LOCAL_OUT 兩個(gè) HOOK,作用是修改 數(shù)據(jù)報(bào)報(bào)頭中的一些值。2. 表的實(shí)現(xiàn) 表的基本數(shù)據(jù)結(jié)構(gòu)是 ipt_tabl(e 位于 include/linux/netfilter_ipv4/ip_tables.h, Line413):struct ipt_tablestruct list_head list; / 一個(gè)雙向鏈表char nameIPT_TABLE_MAXNAMELEN; / 被用戶空間使用的表函數(shù)的名字stru

30、ct ipt_replace *table; / 表初始化的模板,定義了一個(gè)初始化用的該 / 表的所 默認(rèn)的 HOOK 所包含的規(guī)則等信息,/ 用戶通過系統(tǒng)調(diào)用進(jìn)行表的替換時(shí)也要用unsigned int valid_hooks; /表所監(jiān)聽的HOOK,實(shí)質(zhì)是一個(gè)位圖rwlock_t lock; / 整個(gè)表的讀/寫自旋鎖struct ipt_table_info *private; / 表所存儲(chǔ)的數(shù)據(jù)信息,也就是實(shí)際的數(shù)據(jù)區(qū),/ 僅在處理 ipt_table 的代碼內(nèi)部使用struct module *me; / 如果是模塊,那么取 THIS_MODULE,否則取 NULL;其中:unsign

31、ed int valid_hooks;這個(gè)位圖有兩個(gè)作用:一是檢查Netfilter中哪些 HOOK對(duì)應(yīng)著合法的entries ;二是用來為ipt_match以及ipt_target數(shù)據(jù)結(jié) 構(gòu)中的checkentry()函數(shù)核算可能的HOOK。struct module *me;當(dāng)取值為 THIS_MODULE 時(shí),可以阻止用戶 rmmod 一個(gè)仍然被某個(gè)規(guī)則指向的模塊的嘗試。struct ipt_replace *table;的數(shù)據(jù)結(jié)構(gòu)是被用戶空間用來替換一個(gè)表的,其 定義位于 include/linux/netfilter_ipv4/ip_tables.h, Line230:struct

32、ipt_replacechar nameIPT_TABLE_MAXNAMELEN;unsigned int valid_hooks;unsigned int num_entries; / 規(guī)則表入口的數(shù)量unsigned int size; / 新的規(guī)則表的總大小/* Hook entry points. */unsigned int hook_entryNF_IP_NUMHOOKS; / 表所監(jiān)聽 HOOK 的規(guī)則入口,/ 是對(duì)于 entries 的偏移unsigned int underflowNF_IP_NUMHOOKS; / 規(guī)則表的最大下界unsigned int num_count

33、ers; / 舊的計(jì)數(shù)器數(shù)目,即當(dāng)前的舊 entries 的數(shù)目struct ipt_counters *counters; / 舊的計(jì)數(shù)器struct ipt_entry entries0; / 規(guī)則表入口; 上文所提到的 filter 、nat 和 mangle 表分別是 ipt_table 這個(gè)數(shù)據(jù)結(jié)構(gòu)的三個(gè) 實(shí)例:packet_filter (位于 net/ipv4/netfilter/iptable_filter.c, Line84)、nat_table (位于 net/ipv4/netfilter/ip_nat_rule.c, Line104) 以及 packet_mangler

34、(位 于 net/ipv4/netfilter/iptable_mangle.c, Line117)ipt_table_info (位于 net/ipv4/netfilter/ip_tables.c, Line86)是實(shí)際描述規(guī)則 表的數(shù)據(jù)結(jié)構(gòu):struct ipt_table_infounsigned int size;unsigned int number; / 表項(xiàng)的數(shù)目unsigned int initial_entries; / 初始表項(xiàng)數(shù)目unsigned int hook_entryNF_IP_NUMHOOKS; / 所監(jiān)聽 HOOK 的規(guī)則入口unsigned int unde

35、rflowNF_IP_NUMHOOKS; / 規(guī)則表的最大下界char entries0 cacheline_aligned; / 規(guī)則表入口,即真正的規(guī)則存儲(chǔ)結(jié)構(gòu) /ipt_entry組成塊的起始地址,對(duì)多CPU,每個(gè)CPU對(duì)應(yīng)一個(gè);規(guī)則的實(shí)現(xiàn)IPTables 中的規(guī)則表可以在用戶空間中使用,但它所采用的數(shù)據(jù)結(jié)構(gòu)與內(nèi) 核空間中的是一樣的,只不過有些成員不會(huì)在用戶空間中使用。一個(gè)完整的規(guī)則由三個(gè)數(shù)據(jù)結(jié)構(gòu)共同實(shí)現(xiàn),分別是:o 一個(gè) ipt_entry 結(jié)構(gòu),存儲(chǔ)規(guī)則的整體信息;o 0或多個(gè)ipt_entry_match結(jié)構(gòu),存放各種match,每個(gè)結(jié)構(gòu)都可以 存放任意的數(shù)據(jù),這樣也就擁有了良好的

36、可擴(kuò)展性;1 個(gè) ipt_entry_target 結(jié)構(gòu),存放規(guī)則的 target ,類似的,每個(gè)結(jié)構(gòu) 也可以存放任意的數(shù)據(jù)。下面將依次對(duì)這三個(gè)數(shù)據(jù)結(jié)構(gòu)進(jìn)行分析:i. 存儲(chǔ)規(guī)則整體的結(jié)構(gòu)ipt_entry,其形式是一個(gè)鏈表(位于 include/linux/netfilter_ipv4/ip_tables.h,Line122):struct ipt_entrystruct ipt_ip ip;unsigned int nfcache;u_int16_t target_offset;u_int16_t next_offset;unsigned int comefrom;struct ipt_co

37、unters counters;unsigned char elems0;其成員如下:o struct ipt_ip ip;:這是對(duì)其將要進(jìn)行匹配動(dòng)作的IP數(shù)據(jù)報(bào)報(bào)頭的 描述,其定義于 include/linux/netfilter_ipv4/ip_tables.h, Line122, 其成員包括源/目的IP及其掩碼,出入端口及其掩碼,協(xié)議族、標(biāo) 志/取反 flag 等信息。o unsigned int nfcache; : HOOK函數(shù)返回的cache標(biāo)識(shí),用以說明 經(jīng)過這個(gè)規(guī)則后數(shù)據(jù)報(bào)的狀態(tài),其可能值有三個(gè),定義于 include/linux/netfilter.h, Line23:#de

38、fine NFC_ALTERED 0 x8000 /已改變 #define NFC_UNKNOWN 0 x4000 /不確定另一個(gè)可能值是 0,即沒有改變。o u_intl6_t target_offset;:指出了 target 的數(shù)據(jù)結(jié)構(gòu) ipt_entry_target 的起始位置,即從 ipt_entry 的起始地址到 match 存儲(chǔ)結(jié)束的位置o u_int16_t next_offset;:指出了整條規(guī)則的大小,也就是下一條規(guī) 則的起始地址,即 ipt_entry 的起始地址到 match 偏移再到 target 存 儲(chǔ)結(jié)束的位置o unsigned int comefrom;:所

39、謂的“back pointer據(jù)引用此變量的 代碼(主要是 net/ipv4/netfilter/ip_tables.c 中)來看,它應(yīng)該是指向 數(shù)據(jù)報(bào)所經(jīng)歷的上一個(gè)規(guī)則地址,由此實(shí)現(xiàn)對(duì)數(shù)據(jù)報(bào)行為的跟蹤o struct ipt_counters counters;:說明了匹配這個(gè)規(guī)則的數(shù)據(jù)報(bào)的計(jì)數(shù) 以及字節(jié)計(jì)數(shù)(定義于 include/linux/netfilter_ipv4/ip_tables.h, Line100)o unsigned char elems0;:表示擴(kuò)展的match開始的具體位置(因 為它是大小不確定的),當(dāng)然,如果不存在擴(kuò)展的match那么就是 target 的開始位置i

40、.擴(kuò)展match的存儲(chǔ)結(jié)構(gòu)ipt_entry_match,位于 include/linux/netfilter_ipv4/ip_tables.h, Line48:i.struct ipt_entry_match union struct u_int16_t match_size;char nameIPT_FUNCTION_MAXNAMELEN; user;struct u_int16_t match_size;struct ipt_match *match; kernel;u_int16_t match_size; /總長度 u;unsigned char data0;其中描述match大小的

41、u_intl6_t match_size;,從涉及這個(gè)變量的源碼看 來,在使用的時(shí)候需要注意使用一個(gè)宏IPT_ALIGN (位于 include/linux/netfilter_ipv4/ip_tables.h, Line445)來進(jìn)行 4 的對(duì)齊處理(0 x3 & Oxfffffffc),這應(yīng)該是由于match、target擴(kuò)展后大小的不確定性決定的。在結(jié)構(gòu)中,用戶空間與內(nèi)核空間為不同的實(shí)現(xiàn),內(nèi)核空間中的描述擁有 更多的信息。在用戶空間中存放的僅僅是match的名稱,而在內(nèi)核空間中存放的 則是一個(gè)指向ipt_match結(jié)構(gòu)的指針結(jié)構(gòu) ipt_match 位于 include/linux/ne

42、tfilter_ipv4/ip_tables.h, Line342:struct ipt_matchstruct list_head list;const char nameIPT_FUNCTION_MAXNAMELEN;int (*match)(const struct sk_buff *skb,const struct net_device *in,const struct net_device *out,const void *matchinfo, / 指向規(guī)則中 match 數(shù)據(jù)的指針,/具體是什么數(shù)據(jù)結(jié)構(gòu)依情況而定int offset, / IP 數(shù)據(jù)報(bào)的偏移const void *

43、hdr, / 指向協(xié)議頭的指針u_int16_t datalen, /實(shí)際數(shù)據(jù)長度,即數(shù)據(jù)報(bào)長度-IP頭長度int *hotdrop);int (*checkentry)(const char *tablename, / 可用的表const struct ipt_ip *ip,void *matchinfo, unsigned int matchinfosize, unsigned int hook_mask); / 對(duì)應(yīng) HOOK 的位圖void (*destroy)(void *matchinfo, unsigned int matchinfosize); struct module *m

44、e;其中幾個(gè)重要成員:o int (*match)(); :指向用該match進(jìn)行匹配時(shí)的匹配函數(shù)的指針,match相關(guān)的核心實(shí)現(xiàn)。返回0時(shí)hotdrop置1,立即丟棄數(shù)據(jù) 報(bào);返回非 0 表示匹配成功。o int (*checkentry)(); :當(dāng)試圖插入新的match表項(xiàng)時(shí)調(diào)用這個(gè)指針?biāo)赶虻暮瘮?shù),對(duì)新的 match 表項(xiàng)進(jìn)行有效性檢查,即檢查參 數(shù)是否合法;如果返回false,規(guī)則就不會(huì)被接受(譬如,一個(gè)TCP 的 match 只會(huì) TCP 包,而不會(huì)接受其它)。o void (*destroy)();:當(dāng)試圖刪除一個(gè)使用這個(gè)match的表項(xiàng)時(shí),即模塊釋放時(shí),調(diào)用這個(gè)指針?biāo)赶虻暮瘮?shù)

45、。我們可以在 checkentry 中動(dòng)態(tài)地分配資源,并在 destroy 中將其釋放。i. 擴(kuò)展target的存儲(chǔ)結(jié)構(gòu)ipt_entry_target,位于 include/linux/netfilter_ipv4/ip_tables.h, Line71,這個(gè)結(jié)構(gòu)與 ipt_entry_match 結(jié)構(gòu)類似,同時(shí)其中描述內(nèi)核空間target的結(jié)構(gòu)ipt_target (位于 include/linux/netfilter_ipv4/ip_tables.h, Line375) 也與 ipt_match 類似,只 不過其中的target()函數(shù)返回值不是0/1,而是verdict。而 targe

46、t 的實(shí)際使用中,是用一個(gè)結(jié)構(gòu) ipt_standard_target 專門來描述, 這才是實(shí)際的 target 描述數(shù)據(jù)結(jié)構(gòu)(位于 include/linux/netfilter_ipv4/ip_tables.h , Line94),它實(shí)際上就是一個(gè) ipt_entry_target 加一個(gè) verdict。 其中成員 verdict 這個(gè)變量是一個(gè)很巧妙的設(shè)計(jì),也是一個(gè)非常重要的東 東,其值的正負(fù)有著不同的意義。我沒有找到這個(gè)變量的中文名稱,在內(nèi) 核開發(fā)者的新聞組中稱這個(gè)變量為“a magic number”。它的可能值包括 IPT_CONTINUE、IPT_RETURN 以及前文所述的

47、NF_DROP 等值,那么 它的作用是什么呢?o 由于 IPTables 是在用戶空間中執(zhí)行的,也就是說 Netfilter/IPTables 這個(gè)框架需要用戶態(tài)與內(nèi)核態(tài)之間的數(shù)據(jù)交換以及識(shí)別。而在具體 的程序中,verdict 作為struct ipt_standard_target的一個(gè)成員,也是 對(duì)于struct ipt_entry_target中的target。函數(shù)的返回值。這個(gè)返回值 標(biāo)識(shí)的是target()所對(duì)應(yīng)的執(zhí)行動(dòng)作,包括系統(tǒng)的默認(rèn)動(dòng)作以及外 部提交的自定義動(dòng)作。o但是,在用戶空間中提交的數(shù)據(jù)往往是類似于“ ACCPET”之類的 字符串,在程序處理時(shí)則是以 #define N

48、F_ACCEPT 1的形式來進(jìn) 行的;而實(shí)際上,以上那些執(zhí)行動(dòng)作是以鏈表的數(shù)據(jù)結(jié)構(gòu)進(jìn)行存儲(chǔ) 的,在內(nèi)核空間中表現(xiàn)為偏移。o 于是, verdict 實(shí)際上描述了兩個(gè)本質(zhì)相同但實(shí)現(xiàn)不同的值:一個(gè)是 用戶空間中的執(zhí)行動(dòng)作,另一個(gè)則是內(nèi)核空間中在鏈表中的偏移 而這就出現(xiàn)了沖突。o 解決這種沖突的方法就是:用正值表示內(nèi)核中的偏移,而用負(fù)值來 表示數(shù)據(jù)報(bào)的那些默認(rèn)動(dòng)作,而外部提交的自定義動(dòng)作則也是用正 值來表示。這樣,在實(shí)際使用這個(gè)verdict時(shí),我們就可以通過判 斷值的正負(fù)來進(jìn)行相應(yīng)的處理了。o 位于 net/ipv4/netfilter/ip_tables.h 中的函數(shù) ipt_do_table(

49、)中有一個(gè)典 型的verdict使用(Line335,其中v是一個(gè)verdict的實(shí)例):if (v !=IPT_RETURN) verdict = (unsigned)(-v) - 1;break;其中的 IPT_RETURN 定義為:#define IPT_RETURN (-NF_MAX_VERDICT 1)而宏NF_MAX_VERDICT實(shí)際上就是:#define NF_MAX_VERDICT NF_REPEAT這樣,實(shí)際上IPT_RETURN的值就是-NF_REPEAT-1,也就是對(duì)應(yīng) REPEAT,這就是對(duì)執(zhí)行動(dòng)作的實(shí)際描述;而我們可以看到,在下面對(duì)verdict 進(jìn)行賦值時(shí),它所使

50、用的值是(unsigned)(-v) - 1,這就是在內(nèi)核中實(shí)際對(duì)偏移進(jìn) 行定位時(shí)所使用的值。那么總之呢,表和規(guī)則的實(shí)現(xiàn)如圖 HYPERLINK /photo/24896_061206192551.jpg /photo/24896_061206192551.jpg 所示:從上圖中不難發(fā)現(xiàn), match 的定位如下:O 起始地址為:當(dāng)前規(guī)則(起始)地址+ sizeof(struct ipt_entry); o結(jié)束地址為:當(dāng)前規(guī)則(起始)地址+ipt_entry-target_offset; o 每一個(gè) match 的大小為: ipt_entry_match-u.match_size。target

51、 的定位則為:o 起始地址為 match 的結(jié)束地址,即:當(dāng)前規(guī)則(起始)地址 ipt_entry- target_offset;o 結(jié)束地址為下一條規(guī)則的起始地址,即:當(dāng)前規(guī)則(起始)地址 ipt_entry- next_offset;o 每一個(gè) target 的大小為: ipt_entry_target-u.target_size。這些對(duì)于理解 match 以及 target 相關(guān)函數(shù)的實(shí)現(xiàn)是很有必要明確的。同時(shí),include/linux/netfilter_ipv4/ip_tables.h 中提供了三個(gè)“helper functions”可用于使對(duì)于entry、tartget和matc

52、h的操作變得方便,分別是:函數(shù)ipt_get_target(): Line274,作用是取得target的起始地址,也就是上 面所說的當(dāng)前規(guī)則(起始)地址+ipt_entry- target_offset ;宏 IPT_MATCH_ITERATE(): Line281,作用是遍歷規(guī)則的所有 match, 并執(zhí)行同一個(gè)(參數(shù)中)給定的函數(shù)。其參數(shù)為一個(gè) ipt_entry_match 結(jié)構(gòu) 和一個(gè)函數(shù),以及函數(shù)需要的參數(shù)。當(dāng)返回值為 0 時(shí),表示遍歷以及函數(shù) 執(zhí)行順利完成;返回非 0 值時(shí)則意味著出現(xiàn)問題已終止。宏IPT_ENTRYTERATE(): Line300,作用是遍歷一個(gè)表中的所有規(guī)則

53、, 并執(zhí)行同一個(gè)給定的函數(shù)。其參數(shù)為一個(gè) ipt_entry 結(jié)構(gòu)、整個(gè)規(guī)則表的 大小,以及一個(gè)函數(shù)和其所需參數(shù)。其返回值的意義與宏 IPT_MATCH_ITERATE ()類似。o 那么如何保證傳入的 ipt_entry 結(jié)構(gòu)是整個(gè)規(guī)則表的第一個(gè)結(jié)構(gòu)呢? 據(jù)源碼看來,實(shí)際調(diào)用這個(gè)宏的時(shí)候傳入的第一個(gè)參數(shù)都是某個(gè) ipt_table_info 結(jié)構(gòu)的實(shí)例所指向的 entries 成員,這樣就保證了對(duì)整 個(gè)規(guī)則表的完整遍歷。規(guī)則的使用當(dāng)一個(gè)特定的 HOOK 被激活時(shí),數(shù)據(jù)報(bào)就開始進(jìn)入 Netfilter/IPTables 系 統(tǒng)進(jìn)行遍歷,首先檢查struct ipt_ip ip,然后數(shù)據(jù)報(bào)將依次

54、遍歷各個(gè)match,也 就是struct ipt_entry_match,并執(zhí)行相應(yīng)的match函數(shù),即ipt_match結(jié)構(gòu)中的 *match 所指向的函數(shù)。當(dāng) match 函數(shù)匹配不成功時(shí)返回 0,或者 hotdrop 被置為 1 時(shí),遍歷將會(huì)停止。對(duì)match的遍歷完成后,會(huì)開始檢查struct ipt_entry_target,其中如果是 一個(gè)標(biāo)準(zhǔn)的 target,那么會(huì)檢查struct ipt_standard_target 中的 verdict,如果 verdict 值是正的而偏移卻指向不正確的位置,那么 ipt_entry 中的 comefrom 成員就有了 用武之地?cái)?shù)據(jù)報(bào)返回所

55、經(jīng)歷的上一個(gè)規(guī)則。對(duì)于非標(biāo)準(zhǔn)的 target 呢,就會(huì)調(diào) 用target()函數(shù),然后根據(jù)其返回值進(jìn)行后面的處理。規(guī)則的擴(kuò)展Netfilter/IPTables提供了對(duì)規(guī)則進(jìn)行擴(kuò)展的機(jī)制:可以寫一個(gè)LKM來擴(kuò)展 內(nèi)核空間的功能,也可以寫一個(gè)共享庫來擴(kuò)展用戶空間中 IPTables 的功能。1. 內(nèi)核的擴(kuò)展要對(duì)內(nèi)核空間的功能進(jìn)行擴(kuò)展,實(shí)際上就是寫一個(gè)具有表、match以及 target 增加功能的模塊,相關(guān)的函數(shù)為(位于 net/ipv4/netfilter/ip_tables.c, Line1318 to 1444): ipt_register_table()、ipt_unregister_t

56、able(),參數(shù)為 struct ipt_table *。ipt_register_table()函數(shù)是這三對(duì)函數(shù)中最復(fù)雜的一個(gè),涉及 了內(nèi)存、信號(hào)量等方方面面的東西,但總起來說就做了初始 化表以及加入雙向鏈表兩件事。其復(fù)雜一是因?yàn)樯婕暗蕉?CPU 的處理(每個(gè) CPU 擁有各自 獨(dú)立的“規(guī)則空間”),需要首先將新的 entries 放入第一 個(gè) CPU 空間,在檢查完畢后再復(fù)制到其他 CPU 中;二是就 是上面所說對(duì)新 table 各個(gè) entry 的檢查,包括邊界檢查以及 完整性檢查等。其中的重要函數(shù)有這么幾個(gè): translate_table()(位于 net/ipv4/netfilt

57、er/ip_tables.c, Line797):這個(gè)函數(shù)的主要作用是檢查并應(yīng)用用戶 空間傳來的規(guī)則 :1.1.1.對(duì)新表進(jìn)行邊界檢查(由宏 IPT_ENTRY_ITERATE() 調(diào)用函數(shù) check_entry_size_and_blocks(),位于 net/ipv4/netfilter/ip_tables.c , Line732) ,包括對(duì)齊、 過大過小等,特別是保證賦給 hook_entries 和 underflows 值的正確性。調(diào)用函數(shù) make_source_chains()(位于 net/ipv4/netfilter/ip_tables.c, Line499)檢查新的表中

58、是否存在規(guī)則環(huán),同時(shí)將 HOOK 的規(guī)則遍歷順序存 入 comefrom 變量。(這個(gè)函數(shù)我沒有仔細(xì)看,只是 大概略了一下)對(duì) ipt_entry 依次進(jìn)行 ipt_ip 頭、 match 以及 target 的 完整性檢查(由宏IPT_ENTRY_ITERATE()調(diào)用函數(shù) check_entry(),位于 net/ipv4/netfilter/ip_tables.c, Line676),保證 ipt_entry 的正確性。將正確的 ipt_tables 復(fù)制給其他的 CPU。這個(gè)函數(shù)另外還在do_replace()函數(shù)(僅在一個(gè)源碼中沒有被調(diào)用過的函數(shù)中被 調(diào)用,不予分析)中被調(diào)用。o r

59、eplace_table()(位于 net/ipv4/netfilter/ip_tables.c, Line877):這個(gè)函數(shù)的主要作用是:將得到模塊初 始值的ipt_table_info結(jié)構(gòu)(newinfo)中的值傳給 ipt_table 中的 private,并返回 ip_table 中舊的 private。 list_prepend()(位于 include/linux/netfilter_ipv4/listhelp.h, Line75):在這 個(gè)函數(shù)被調(diào)用之前,整個(gè)初始化的過程就已經(jīng)結(jié)束了 這個(gè)函數(shù)的主要作用是:互斥地調(diào)用 Linux 源碼中的 list_add()函數(shù)(位于 incl

60、ude/linux/list.h, Line55), 將新的 table 加入到雙向鏈表之中。o ipt_register_match()、ipt_unregister_match(),參數(shù)為 struct ipt_match *。o ipt_register_target()、ipt_unregister_target(),參數(shù)為 struct ipt_target *這三對(duì)函數(shù)除了 ipt_register_table()外的5個(gè)函數(shù)主要就是互斥地將 table/match/target 加入到雙向鏈表中或者從雙向鏈表中刪除。其中向雙向鏈表中加入新節(jié)點(diǎn)是通過調(diào)用list_named_ins

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論