netfilter 連結跟蹤機制與NAT原理
核心版本:2.6.12
1.連結跟蹤 conntrack
1.1.netfilter框架
5個鏈:
NF_IP_PRE_ROUTING:資料包進入路由表之前
NF_IP_LOCAL_IN:通過路由表後目的地為本機
NF_IP_FORWARD:通過路由表後,目的地不為本機
NF_IP+LOCAL_OUT:由本機產生,向外轉發
NF_IP_POST_ROUTING:傳送到網絡卡介面之前。
4個表:
filter,nat,mangle,raw,預設表是filter(沒有指定表的時候就是filter表)。
filter:
nat: 用於nat功能(埠對映,地址對映等)
mangle: 用於對特定資料包的修改
raw:優先順序最高,設定raw時一般是為了不再讓iptables做資料包的連結跟蹤處理,提高效能
表和鏈的關係:(raw連線跟蹤在下面單獨說明)
資料包流程: 當資料包到達防火牆時,如果MAC地址符合,就會由核心裡相應的驅動程式接收,然後會經過一系列操作,從而決定是傳送給本地的程式,還是轉發給其他機子,還是其他的什麼。
首先來看一個以本地為目的的資料包,它要經過以下步驟才能到達要接收它的程式 :
Step |
Table |
Chain |
Comment |
1 |
線上路上傳輸(比如,Internet) |
||
2 |
進入介面 (比如, eth0) |
||
3 |
mangle |
PREROUTING |
這個鏈用來mangle資料包,比如改變TOS等 |
4 |
nat |
PREROUTING |
這個鏈主要用來做DNAT。不要在這個鏈做過慮操作,因為某些情況下包會溜過去。 |
5 |
路由判斷,比如,包是發往本地的,還是要轉發的。 |
||
6 |
mangle |
INPUT |
在路由之後,被送往本地程式之前,mangle資料包。 |
7 |
filter |
INPUT |
所有以本地為目的的包都要經過這個鏈,不管它們從哪兒來,對這些包的過濾條件就設在這裡。 |
8 |
到達本地程式了(比如,服務程式或客戶程式) |
接著看看以以本地為源的資料包,它需要經過下面的步驟才能傳送出去:
Step |
Table |
Chain |
Comment |
1 |
本地程式(比如,服務程式或客戶程式) |
||
2 |
路由判斷,要使用源地址,外出介面,還有其他一些資訊。 |
||
3 |
mangle |
OUTPUT |
在這兒可以mangle包。建議不要在這兒做過濾,可能有副作用。 |
4 |
nat |
OUTPUT |
這個鏈對從防火牆本身發出的包進行DNAT操作。 |
5 |
filter |
OUTPUT |
對本地發出的包過濾。 |
6 |
mangle |
POSTROUTING |
這條鏈主要在包DNAT之後(譯者注:作者把這一次DNAT稱作實際的路由,雖然在前面有一次路由。對於本地的包,一旦它被生成,就必須經過路由程式碼的處理,但這個包具體到哪兒去,要由NAT程式碼處理之後才能確定。所以把這稱作實際的路由。),離開本地之前,對包 mangle。有兩種包會經過這裡,防火牆所在機子本身產生的包,還有被轉發的包。 |
7 |
nat |
POSTROUTING |
在這裡做SNAT。但不要在這裡做過濾,因為有副作用,而且有些包是會溜過去的,即使你用了DROP策略。 |
8 |
離開介面(比如: eth0) |
||
9 |
線上路上傳輸(比如,Internet) |
最後我們看一個目的是另一個網路中的一臺機子:
Step |
Table |
Chain |
Comment |
1 |
線上路上傳輸(比如,Internet) |
||
2 |
進入介面(比如, eth0) |
||
3 |
mangle |
PREROUTING |
mangle資料包,,比如改變TOS等。 |
4 |
nat |
PREROUTING |
這個鏈主要用來做DNAT。不要在這個鏈做過慮操作,因為某些情況下包會溜過去。稍後會做SNAT。 |
5 |
路由判斷,比如,包是發往本地的,還是要轉發的。 |
||
6 |
mangle |
FORWARD |
包繼續被髮送至mangle表的FORWARD鏈,這是非常特殊的情況才會用到的。在這裡,包被mangle(還記得mangle的意思嗎)。這次mangle發生在最初的路由判斷之後,在最後一次更改包的目的之前(譯者注:就是下面的FORWARD鏈所做的,因其過濾功能,可能會改變一些包的目的地,如丟棄包)。 |
7 |
filter |
FORWARD |
包繼續被髮送至這條FORWARD鏈。只有需要轉發的包才會走到這裡,並且針對這些包的所有過濾也在這裡進行。注意,所有要轉發的包都要經過這裡,不管是外網到內網的還是內網到外網的。在你自己書寫規則時,要考慮到這一點。 |
8 |
mangle |
POSTROUTING |
這個鏈也是針對一些特殊型別的包(譯者注:參考第6步,我們可以發現,在轉發包時,mangle表的兩個鏈都用在特殊的應用上)。這一步mangle是在所有更改包的目的地址的操作完成之後做的,但這時包還在本地上。 |
9 |
nat |
POSTROUTING |
這個鏈就是用來做SNAT的,當然也包括Masquerade(偽裝)。但不要在這兒做過濾,因為某些包即使不滿足條件也會通過。 |
10 |
離開介面(比如: eth0) |
||
11 |
又線上路上傳輸了(比如,LAN) |
就如你所見的,包要經歷很多步驟,而且它們可以被阻攔在任何一條鏈上,或者是任何有問題的地方。
1.2.連線跟蹤(CONNTRACK),顧名思義,就是跟蹤並且記錄連線狀態。Linux為每一個經過網路堆疊的資料包,生成一個新的連線記錄項 (Connection entry)。此後,所有屬於此連線的資料包都被唯一地分配給這個連線,並標識連線的狀態。連線跟蹤是防火牆模組的狀態檢測的基礎,同時也是地址轉換中實 現SNAT和DNAT的前提。那麼Netfilter又是如何生成連線記錄項的呢?每一個數據,都有“來源”與“目的”主機,發起連線的主機稱為“來源”,響應“來源”的請求的主機即為目的,所謂生成記錄項,就是對每一個這樣的連線的產生、傳輸及終止進行跟蹤記錄。由所有記錄項產生的表,即稱為連線跟蹤表。
1.2.1連線記錄
在 Linux 核心中,連線記錄由ip_conntrack結構表示,其結構如下圖所示。在該結構中,包含一個nf_conntrack型別的結構,其記錄了連線記錄被公開應用的計數,也方便其他地方對連線跟蹤的引用。每個連線記錄都對應一個指向連線超時的函式指標,當較長時間內未使用該連線,將呼叫該指標所指向的函式。如果針對某種協議的連線跟蹤需要擴充套件模組的輔助,則在連線記錄中會有一指向ip_conntrack_helper 結構體的指標。連線記錄中的結構體ip_conntrack_tuple_hash實際記錄了連線所跟蹤的地址資訊(源和目的地址)和協議的特定資訊(埠)。所有連線記錄的ip_conntrack_tuple_hash以雜湊形式儲存在連線跟蹤表中(ip_conntrack記錄存放在堆裡面)。
1.2.3連結跟蹤表
連線跟蹤表是記錄所有連線記錄的散列表,其由全域性變數ip_conntrack_hash所指向。連線跟蹤表實際是一個以雜湊值排列的雙向連結串列陣列,連結串列中的元素即為連線記錄所包含的ip_conntrack_tuple_hash結構。
1.3傳輸協議
連線跟蹤機制可以支援多種傳輸協議,不同的協議所採用的跟蹤方式會有所不同。傳輸協議用結構ip_conntrack_protocol 儲存,所有的已註冊的傳輸協議列表由全域性變數ip_ct_protos 所指向的一維陣列儲存,且按照協議號的順序依次排列。函式ip_conntrack_protocol_register()和ip_conntrack_protocol_unregister()用於向協議列表中新增或刪除一個協議。
資料結構部分總結:
1.整個hash表用ip_conntrack_hash 指標陣列來描述,它包含了ip_conntrack_htable_size個元素,預設是根據記憶體大小計算出來的;
2. 整個連線跟蹤表的大小使用全域性變數ip_conntrack_max描述,與hash表的關係是ip_conntrack_max = 8 * ip_conntrack_htable_size;
3. hash連結串列的每一個節點是一個struct ip_conntrack_tuple_hash結構,它有兩個成員,一個是list,一個是tuple;
4.Netfilter將每一個數據包轉換成tuple,再根據tuple計算出hash值,這樣,就可以使用ip_conntrack_hash[hash_id]找到hash表中連結串列的入口,並組織連結串列;
5. 找到hash表中連結串列入口後,如果連結串列中不存在此“tuple”,則是一個新連線,就把tuple插入到連結串列的合適位置;
6. 圖中兩個節點tuple[ORIGINAL]和tuple[REPLY],雖然是分開的,在兩個連結串列當中,但是如前所述,它們同時又被封裝在ip_conntrack結構的tuplehash陣列中;
大家感興趣的肯定是怎麼實現連結跟蹤的,由於篇幅,我省略去連結跟蹤的初始化等等部分,重點講解一下連結跟蹤的實現。
1.4連結跟蹤的實現—ip_conntrack_in()
資料包進入Netfilter後,會呼叫ip_conntrack_in函式,以進入連線跟蹤模組,ip_conntrack_in 主要完成的工作就是判斷資料包是否已在連線跟蹤表中,如果不在,則為資料包分配ip_conntrack,並初始化它,然後,為這個資料包設定連線狀態。
1 unsigned int ip_conntrack_in(unsigned int hooknum, 2 struct sk_buff **pskb, 3 const struct net_device *in, 4 const struct net_device *out, 5 int (*okfn)(struct sk_buff *)) 6 { 7 struct ip_conntrack *ct; 8 enum ip_conntrack_info ctinfo; 9 struct ip_conntrack_protocol *proto; 10 int set_reply; 11 int ret; 12 13 /* 判斷當前資料包是否已被檢查過了 */ 14 if ((*pskb)->nfct) { 15 CONNTRACK_STAT_INC(ignore); 16 return NF_ACCEPT; 17 } 18 19 /* 分片包當會在前一個Hook中被處理,事實上,並不會觸發該條件 */ 20 if ((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) { 21 if (net_ratelimit()) { 22 printk(KERN_ERR "ip_conntrack_in: Frag of proto %u (hook=%u)\n", 23 (*pskb)->nh.iph->protocol, hooknum); 24 } 25 return NF_DROP; 26 } 27 28 /* 將當前資料包設定為未修改 */ 29 (*pskb)->nfcache |= NFC_UNKNOWN; 30 31 /*根據當前資料包的協議,查詢與之相應的struct ip_conntrack_protocol結構*/ 32 proto = ip_ct_find_proto((*pskb)->nh.iph->protocol); 33 34 /* 沒有找到對應的協議. */ 35 if (proto->error != NULL 36 && (ret = proto->error(*pskb, &ctinfo, hooknum)) <= 0) { 37 CONNTRACK_STAT_INC(error); 38 CONNTRACK_STAT_INC(invalid); 39 return -ret; 40 } 41 42 /*在全域性的連線表中,查詢與當前包相匹配的連線結構,返回的是struct ip_conntrack *型別指標,它用於描述一個數據包的連線狀態*/ 43 if (!(ct = resolve_normal_ct(*pskb, proto,&set_reply,hooknum,&ctinfo))) { 44 /* Not valid part of a connection */ 45 CONNTRACK_STAT_INC(invalid); 46 return NF_ACCEPT; 47 } 48 49 if (IS_ERR(ct)) { 50 /* Too stressed to deal. */ 51 CONNTRACK_STAT_INC(drop); 52 return NF_DROP; 53 } 54 55 IP_NF_ASSERT((*pskb)->nfct); 56 57 /*Packet函式指標,為資料包返回一個判斷,如果資料包不是連線中有效的部分,返回-1,否則返回NF_ACCEPT。*/ 58 ret = proto->packet(ct, *pskb, ctinfo); 59 if (ret < 0) { 60 /* Invalid: inverse of the return code tells 61 * the netfilter core what to do*/ 62 nf_conntrack_put((*pskb)->nfct); 63 (*pskb)->nfct = NULL; 64 CONNTRACK_STAT_INC(invalid); 65 return -ret; 66 } 67 68 /*設定應答狀態標誌位*/ 69 if (set_reply) 70 set_bit(IPS_SEEN_REPLY_BIT, &ct->status); 71 return ret; 72 }
在初始化的時候,我們就提過,連線跟蹤模組將所有支援的 協議,都使用struct ip_conntrack_protocol 結構封裝,註冊至全域性陣列ip_ct_protos,這裡首先呼叫函式ip_ct_find_proto根據當前資料包的協議值,找到協議註冊對應的模 塊。然後呼叫resolve_normal_ct 函式進一步處理.
接下來我們再看一下resolve_normal_ct是怎麼實現的:
resolve_normal_ct 函式是連線跟蹤中最重要的函式之一,它的主要功能就是判斷資料包在連線跟蹤表是否存在,如果不存在,則為資料包分配相應的連線跟蹤節點空間並初始化,然後設定連線狀態:
1 CODE:/* On success, returns conntrack ptr, sets skb->nfct and ctinfo */ 2 static inline struct ip_conntrack * 3 resolve_normal_ct(struct sk_buff *skb, 4 struct ip_conntrack_protocol *相關推薦
netfilter 連結跟蹤機制與NAT原理
核心版本:2.6.12 1.連結跟蹤 conntrack 1.1.netfilter框架 5個鏈: NF_IP_PRE_ROUTING:資料包進入路由表之前 NF_IP_LOCAL_IN:通過路由表後目的地為本機 NF_IP_FORWARD
netfilter連結跟蹤實現之ipv4_confirm函式
ipv4_confirm函式註冊在LOCAL_IN鏈、POST_ROUTING鏈,這個是netfiler的兩個出口,從函式名字看得出函式的功能是連結跟蹤確認,下面來分析這個函式。 static struct nf_hook_ops ipv4_conntrack_ops[] __read_most
netfilter連結跟蹤實現之nf_conntrack_in函式
1、資料包方向 要分析連線連結跟蹤的實現我們就要先分析資料包在協議棧中的方向,總的來說主要分為三個方向:本機轉發的資料包、本機接受的資料包、本機產生的資料包,我們之前分析了連線跟蹤只在四個鏈上註冊了鉤子函式,分別是PRE_ROUTING鏈、OUT鏈、LOCAL_IN鏈、POST_ROUTING鏈
簡析CAS機制與實現原理
在學習CAS的過程中,我百思不得其解的一個問題就是在多cpu併發的環境下,CAS如何保證執行緒的安全性呢?關於這個問題下面的兩篇部落格寫的比較不錯,基本把其中的原理解釋清楚了,這裡我只作一個簡單的闡
netfilter之連結跟蹤做nat
上一節我們將了NAT是基於連結跟蹤實現的,當一條連結跟蹤建立要改變它的tuple的reply方向才能做nat,這個連結跟蹤的nat是函式nf_nat_setup_info實現 1、nf_nat_setup_info nf_nat_setup_info對連結跟蹤的做NAT,只會改變連結跟蹤re
緩存機制與局部性原理
緩存命中 存儲 讀寫 依賴 速度 網絡 表現 二維數組 文件 http://www.cnblogs.com/jqctop1/p/4714116.html 1. 局部性原理 局部性原理是指計算機在執行某個程序時,傾向於使用最近使用的數據。局部性原理有兩種表現形式:時間局部
php運行機制與原理
數據結構 機制 二進制 純c 轉換 請求 程序 輸出 ont php運行機制與原理: PHP總共有三個模塊:內核、Zend引擎、以及擴展層; 1. PHP內核用來處理請求、文件流、錯誤處理等相關操作; 2. Zend引擎(ZE)用以將源文件轉換成機器語言(二進制),然後
Redis Sentinel實現的機制與原理詳解
過程 正則 發送 進行 還需 生產環境 根據 stat 時間 原文:Redis Sentinel實現的機制與原理詳解序言 Redis-Sentinel是Redis官方推薦的高可用性(HA)解決方案。實際上這意味著你可以使用Sentinel模式創建一個可以不用人為幹預而應對
PHP底層的運行機制與原理
ica 介紹 表數 底層 index 加速 解析 空間 相同 PHP說簡單,但是要精通也不是一件簡單的事。我們除了會使用之外,還得知道它底層的工作原理。PHP是一種適用於web開發的動態語言。具體點說,就是一個用C語言實現包含大量組件的軟件框架。更狹義點看,可以把它認為是一
netfilter的filter表案列與nat表應用
dba tro 常見 war ges pac netfilter let vim 一、fileter表案例 需求:只針對filter表,預設策略INPUT鏈DROP,其他兩個鏈ACCEPT,然後針對192.168.204.0/24開通22端口,對所有網段開放80端口,對所有
PHP 底層的運行機制與原理 --轉
獲取 一次 也不會 mon 指向 nim object logs 其他 發現一片總結的還不錯的文章,記錄一下 PHP說簡單,但是要精通也不是一件簡單的事。我們除了會使用之外,還得知道它底層的工作原理。 PHP是一種適用於web開發的動態語言。具體點說,就是一個用C語言實現包
php--->底層的運行機制與數據結構原理
組成 C/C++ BE 怎麽 用戶 特定 交互 註意 快速 PHP 底層的運行機制與數據結構原理 1. PHP的設計理念及特點 多進程模型:由於PHP是多進程模型,不同請求間互不幹涉,這樣保證了一個請求掛掉不會對全盤服務造成影響,當然,隨著時代發展,PHP也早已支持多線程
PHP的運行機制與原理(底層)
富文本 作用域 服務 ssi 關聯 too 使用 index unset 說到php的運行機制還要先給大家介紹php的模塊,PHP總共有三個模塊:內核、Zend引擎、以及擴展層;PHP內核用來處理請求、文件流、錯誤處理等相關操作;Zend引擎(ZE)用以將源文件轉換成機器語
HTTP緩存機制與原理
png ron req https fun 每次 rman get 數據 緩存前言 Web緩存大致可以分為:數據庫緩存、瀏覽器緩存、服務器緩存(CDN、代理服務器緩存) 而瀏覽器緩存也有很多方式,比如:HTTP緩存、localstrong、cookie等,下面將側重於描述
JVM原理(二)類載入機制與GC演算法
一. 類的載入機制 過程 將.class的二進位制資料讀入記憶體,放入方法區中 在堆中建立一個java.lang.Class物件,封裝類在方法區中的資料結構,並提供訪問方法區資料結構的介面 類的生命週期 類的載入過程
ElasticSearch教程——filter執行原理深度剖析(bitset機制與caching機制)
ElasticSearch彙總請檢視:ElasticSearch教程——彙總篇 (1)在倒排索引中查詢搜尋串,獲取document list date來舉例 word doc1 &nb
PHP 底層的執行機制與原理解析(轉載)
我的另一篇文章:PHP底層工作原理 兩篇結合起來看,會更加好理解。 由於本人資料結構方面知識,淺薄,後面的尚未研究 關於 hash table ,這有個文章可以學習:HashTable原理和底層實現 關於 zval 可以研讀這個:入理解PHP7核心之zval
NAT 原理與NAT穿越
轉自:https://blog.csdn.net/whoamiyang/article/details/51992208?utm_source=blogxgwz6 最近在看負載均衡方面的東西中很多都提到了NAT穿越,特意在此總結一下: 先做一個約定: 內網A中有:A1(192.168.30.11
Kafka Partition儲存機制與高吞吐率原理
一、Topic定義與Partition儲存機制 Topic在邏輯上可以被認為是一個管道,每條生產/消費都必須指明Topic,也就是指定這條訊息應該在哪條管道進行傳輸。 為了使得Kafka的吞吐率可以線性提高,物理上把Topic分成一個或多個Partition,每個Partition在物理上對
Java中的類載入和Class.forName();java反射機制與原理
對於大部分人來說,第一次見到class.forName(String className)這句程式碼應該是在使用jdbc方式連線資料庫的時候。但這句程式碼本質上是什麼含義,做了什麼工作呢?本文將回答此問題。 理解Class.forName方法需要一些知識鋪墊,也就是