歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> 基於Linux路由的訪問控制

基於Linux路由的訪問控制

日期:2017/2/28 14:32:44   编辑:Linux教程

聲明

關於訪問控制,人民已經討論了很多的方案,但是千萬不要覺得某種方案是放之四海而皆准的,沒有這樣的東西!RBAC根本不適宏內核協議棧的操作系統(UNIX,Linux,and so on...我可能在之前的文章把它們弄反了,...),但是這並不是每個人民中的一員都知道,包括我自己!

總之,數據包在內核協議棧的處理過程中一定要符合“快,爽”的風格,不能導致後續的數據包排隊,因為不同的數據包可能屬於不同的“業務邏輯”。你不能假設後面數據包所代表的業務邏輯會容忍前面數據包耽擱太多的時間,每人簽署任何協議,對於網絡設備而言,每一個數據包都是平等的,如果高級一點的設備,每一個數據流都是平等的,記住,設備是為轉發數據而生,數據的目的地並不是此設備!

所有的中間設備都TMD是浮雲,一個所謂的WEB加速服務器如果不是利用了cache,那它就是騙局!有什麼能和線速轉發更快的呢?沒有!CAO TMD的沒有!只要Client和Server中間有一台設備,那它就TMD增加了延遲,別指望它能減少延遲,除非上帝便秘!因此,我們在設計中間設備的時候,目標絕對不是神話般的減少延遲,而是“在你能控制的范圍內盡可能的快”,所以,應用程序的那種處理方式就不合適了,別指望用什麼庫可以提高效率,記住,最終的控制權永遠在運營商手中,永遠在那些不懂編程的網管手中,隨便一個人剪斷網線,再怎麼TCP也不能保證你能優雅的發送FIN,誰能控制網絡才能決定一切,網絡的效率永遠比端到端的程序的效率更重要!

本文的目的在於,你能通過一種方式,盡可能保證本地的處理,不考慮別的。在周六的一天的大雨中,激動,悸動!我不屑於網管嘴裡的種種術語,也不怕編程,對於網管和程序員,也許奧托.馮.俾斯麥只能說,哀其不幸,怒其不爭!

我雖然不懂OpenSSL,但是我是程序員!

之後

前面的一篇文章《Linux路由表的抽象擴展應用於nf_conntrack》中指出了可以用Linux的IP路由機制來實現訪問控制列表,即Linux的ACL,在那篇文章中,只是說明了實現的可行性,然而最終,我卻使用Linux的IP路由機制為任意的nf_conntrack保存了一個info字符串而已。本文來具體描述一下如何真的實現訪問控制。

不是有iptables了嗎

為何還要實現一套新的機制?因為:

1.iptables基於Netfilter實現,因此只能實現串行過濾,即一條一條的匹配;

2.匹配速度依賴於iptables規則的配置順序,無法在內核實現統一的優化處理;

3.我不喜歡iptables,它在多核時代已經過時了,雖然可以基於Netfilter開發一個並行版本,但是太難。

因此,為了解決上面的問題,我決定實現一套另外的不依賴Netfilter的訪問控制機制。很顯然,我的目標之一就是在匹配的過程中,多個核心可以被調度起來。

實現原理

實現一套針對IP數據報的訪問控制機制並不是簡單的事情,然而最基本的框架卻是很簡單,那就是基於一個數據包的源IP地址和目標IP地址來決定這個數據包可以做什麼。當然,除了IP地址之外,IP數據報文中的任意一個字段都可以參與匹配,甚至TCP/UDP協議頭的字段也可以參與匹配,是的,但是本文不涉及那種復雜的情況,那些都很容易從本文的思想中擴展出來,因此本文僅僅將IP地址作為匹配要素。

如《Linux路由表的抽象擴展應用於nf_conntrack》 http://www.linuxidc.com/Linux/2014-04/100911.htm 所述,一個Action可以保存在一個路由項當中,但是如果引入另外一個匹配元素目標IP的時候,這個Action將不能再存在於路由項當中了,它將作為源IP地址關聯的路由項和目標IP地址關聯的路由項之間的媒介,指示“該源路由項包含的所有IP地址可以對該目標路由項包含的所有IP地址實施Action”。Action可以是通過,拒絕,地址轉換等所有可能的動作。如果不存在一個Action在兩個路由項之間關聯,則執行默認Action。可想而知,一個Action必須身兼兩職,一方面它加入源路由項的Action鏈表,另一方面它加入目標路由項的Action鏈表中以關聯二者。借用RBAC權限模型的術語,我可以把一個數據包的源IP地址看成是角色,而其訪問的目標IP地址則可以被看作是資源,這裡只是借用一下術語,真正的RBAC要比我這個復雜得多。一會兒我會說,我這個模型著眼在內核實現ACL的方式以及算法,而不是ACL模型本身。

數據結構要比圖示更直接。由於每一個Action都會同時被鏈接到兩個鏈表,因此一個Action命名為Xnode即可:

struct nf_action_node {
//struct list_head list; // 和算法相關,見注解1
struct hlist_node nf_dst;
struct hlist_node nf_src;
struct nf_fib_node *dst_node; //反向指針,算法優化,見查找算法小節
struct nf_fib_node *src_node; //反向指針,算法優化,見查找算法小節
int extra;
//int extra_len;
//char extra[0];
};

其中的nf_dst用於鏈接到目標路由表的某個路由項,而nf_src用於鏈接到源路由表的某個路由項,之所以使用hash list而不是普通的list_head是為了高效,我可不想在內核中遍歷鏈表...當然,除了hash list,你也可以使用任何比較高效的數據結構,比如XX樹之類的,另外,路由表本身也可以不用hash,本文只是恰好使用了它而已,你完全可以使用TRIE樹。上述的action數據結構中,值得注意的是最後注釋掉的兩行,我的原意是可以將任何類型作為action,也就是說你可以將extra定義為任何數據結構,但是由於這只是一篇blog,並沒有逼著我完美的實現,因此點到為止,不再實現。另外,src/dst_node兩個字段則是為了方便從nf_action_node找到它鏈接的兩個路由項,雖然增加了兩個node之間的耦合,但是卻提高了效率,我們不是在OOD,而是在內核編程。

我們已經知道,一個nf_action_node同時鏈接到兩個hlist中,這兩個hlist分為歸兩個路由項所有,接下來就要定義路由項了:

struct nf_fib_node {
struct hlist_node nf_fn_hash;
struct hlist_head *act_list;
__be32 fn_key;
int len;
unsigned int hash_value;
struct nf_action_node *def;
};

更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2014-04/100913p2.htm

Copyright © Linux教程網 All Rights Reserved