歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux綜合 >> Linux資訊 >> 更多Linux

Linux環境下基於策略的路由

原文作者:Matthew G. Marsh  摘要    本文以大量實例為基礎介紹了基於Linux2.2的強大路由功能,它提供的路由功能是很多路由器產品都是難以匹敵的,如果考慮到它的免費性,它的性能價格比更是沒有任何產品可以相比。     目前在計算機網絡中使用的傳統路由算法都是根據IP包目的地址進行路由選擇.然而在現實應用中經常有這樣的需求:進行路由選擇時不僅僅根據數據報的目的地址,而且根據數據報的其他一些特性如:源地址、IP協議、傳輸層端口,甚至是數據包的負載部分內容,這種類型的路由選擇被稱作基於策略的路由。      在Linux中,從2.1版本的內核開始就實現了對基於策略的路由的支持,它是通過使用路由策略數據庫(RPDB,routing policy database)替代傳統的、基於目的地址的路由表來實現的。RPDB通過包含的一些規則來選定合適的IP路由。這些規則可能會包含很多各種不同類型的健值(key),因此這些規則沒有默認的特定次序,規則查找次序或規則優先級都是由網絡或系統管理員設定的。      Linux的RPDB是一個由數字優先級值進行排序的線性規則列表。RPDB能匹配數據報源地址、目的地址、TOS、進入接和fwmark值等。每個路由策略規則由一個選擇器和一個動作指示組成。RPDB按照優先級遞增的順序被掃描,RPDB包含的每條規則的選擇器被應用於數據報的源地址、目的地址、進入接口、TOS和fwmark值。若數據報匹配該規則對應於該規則的動作被執行。若動作成功返回,則規則輸出將是一個有效的路由或是路由查找失敗指示;否則查找RPDB的下一條規則。      當選擇器和一個數據報匹配成功,會執行哪些動作呢?路由軟件的標准動作一般是選擇下一跳地址和輸出接口,可以稱這種動作為“匹配&設置”類型動作。然而Linux采取了更加靈活的方法,在Linux中有多種動作可供選擇。默認的動作是查詢特定的基於目的地址的路由表。因此“匹配&設置”動作就成為Linux路由選擇的最簡單情況。Linux支持多個路由表,每個路由表都包含多條路由信息。也就是Linux的每個路由表都相當於其他操作系統的系統路由表。Linux支持多達255個路由表。(Linux 2.2.12 支持255個路由表,255個匯聚域和232個策略規則優先級 (4294967296 decimal) 。      對於Linux2.1/2.2,啟動時內核將包含一個由三條策略規則組成的默認的RPDB,察看這些默認規則的一個方法是使用命令來列出系統的所有規則:     root@netmonster ip rule list   0:   from all lookup local   32766: from all lookup main   32767: from all lookup default      下面的默認規則在對於理解啟動復雜路由系統是非常重要的。      首先是最高級別的優先級規則,規則策略0:       規則0: 優先級 0   選擇器 = 匹配任何數據報       動作=察看本地路由表(routing table local),ID為255。       local表是保留路由表,包含了到本地和廣播地址的路由。規則0是特殊的規則,不可被刪除或修改。       規則 32766: 優先級 32766   選擇器 = 匹配所有數據報       動作 = 察看主路由表(routing table main), ID為254。       main路由表是默認的標准路由表,其包含所有非策略路由,main表是存放舊的路由命令(route命令)創建的路由。而且任何由ip route命令創建的沒有明確指定路由表的路由都被加入到該路由表中。該規則不能被刪除和被其他規則覆蓋。       規則 32767: 優先級 32767 選擇器 = 匹配所有數據報       動作 = 察看默認路由表(routing table default),ID為253。       default路由表是空的,為最後處理(post-processing)所預留,若前面的默認規則沒有選擇該數據報時保留用作最後的處理。該規則可以被刪除。       不要將路由表和規則混淆,規則是指向路由表的。也許會出現多個規則指向同一個路由表,而有些路由表可能並不被任何規則指向。如果刪除了指向某個路由表的所有規則,則該表將不發生作用,但是表將仍然存在。一個路由表只有在其中包含的所有路由信息被刪除才會消失。       前面提到,Linux策略規對應的動作除了指向一個路由表以外還能是若干種不同的動作。當創建一個策略規則,有如下類型的動作可以選擇:       unicast -- 在該規則指向的路由表中進行標准的路由查找。當一個路由表被指定,這是默認的動作。       blackhole -- 規則動作將僅僅直接丟棄該數據報。       unreachable -- 規則動作產生一條網絡不可達錯誤信息,一個類型為3,代碼為0的ICMP消息被返回給發送者。      prohibit -- 規則動作產生一個通信被禁止的錯誤消息,一個類型為3,代碼為13的ICMP消息被返回給發送者。      其他類型的動作也可以被使用,但是都和策略路由沒有關系。它們被用來在內核中實現其他高級流控制和數據報操作。因為只有一個工具命令:ip,所有的這些類型都是可運用於該命令,但我們僅僅使用和上面有關的部分,可以是返回一條路由或其他若干個動作。       在解釋示例以前,首先看看ip工具命令的語法。ip命令可以用在很多地方,這裡僅僅討論和策略路由相關的部分。都是由root在命令行直接運行的。      首先,看ip addr命令語法:     root@netmonster# ip addr help   Usage: ip addr {adddel} IFADDR dev STRING       ip addr {showflush} [ dev STRING ] [ scope SCOPE-ID ]                 [ to PREFIX ] [ FLAG-LIST ] [ label PATTERN ]   IFADDR := PREFIX ADDR peer PREFIX        [ broadcast ADDR ] [ anycast ADDR ]        [ label STRING ] [ scope SCOPE-ID ]   SCOPE-ID := [ host link global NUMBER ]   FLAG-LIST := [ FLAG-LIST ] FLAG   FLAG := [ permanent dynamic secondary primary          tentative deprecated ]     Example - ip addr add 192.168.1.1/24 dev eth0      該命令將添加IP地址192.168.2.2/24到eth0網卡上.       下面看看ip route命令:      root@netmonster# ip route help   Usage: ip route { list flush } SELECTOR       ip route get ADDRESS [ from ADDRESS iif STRING ]       [ oif STRING ] [ tos TOS ]       ip route { add del replace change append replace        monitor} ROUTE       SELECTOR := [ root PREFIX ] [ match PREFIX ] [ exact PREFIX ]       [ table TABLE_ID ] [ proto RTPROTO ]       [ type TYPE ] [ scope SCOPE ]       ROUTE := NODE_SPEC [ INFO_SPEC ]       NODE_SPEC := [ TYPE ] PREFIX [ tos TOS ]       [ table TABLE_ID ] [ proto RTPROTO ]       [ scope SCOPE ] [ metric METRIC ]       INFO_SPEC := NH OPTIONS FLAGS [ nexthop NH ]...       NH := [ via ADDRESS ] [ dev STRING ] [ weight NUMBER ] NHFLAGS       OPTIONS := FLAGS [ mtu NUMBER ] [ advmss NUMBER ]       [ rtt NUMBER ] [ rttvar NUMBER ]       [ window NUMBER] [ cwnd NUMBER ] [ ssthresh REALM ]       [ realms REALM ]       TYPE := [ unicast local broadcast multicast throw       unreachable prohibit blackhole nat ]       TABLE_ID := [ local main default all NUMBER ]       SCOPE := [ host link global NUMBER ]       FLAGS := [ equalize ]       NHFLAGS := [ onlink pervasive ]       RTPROTO := [ kernel boot static NUMBER ]       Example - ip route add 192.168.2.0/24 via 192.168.1.254       該示例將添加一條通過192.168.1.254到網絡192.168.2.0/24的路由。       最後,看看ip rule命令:     root@netmonster# ip rule help   Usage: ip rule [ list add del ] SELECTOR ACTION   SELECTOR := [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK ]         [ dev STRING ] [ pref NUMBER ]   ACTION := [ table TABLE_ID ] [ nat ADDRESS ]        [ prohibit reject unreachable ]        [ realms [SRCREALM/]DSTREALM ]   TABLE_ID := [ local main default NUMBER ]      Example - ip rule add from 192.168.2.0/24 prio 32777 reject      該命令將丟棄源地址屬於192.168.2.0/24網絡的所有數據報。      在討論了命令語法以後,下面是一些上面命令的示例。      例 1:拒絕訪問Internet      假設有一個防火牆連接本地局域網和Internet,你希望禁止局域網的一個子網訪問Internet。當然這可以通過Linux數據報過濾防火牆來實現。但是下面我們將介紹另外一種實現方法。首先我們來假設有如下的網絡配置:       內部網絡地址      192.168.0.0/16      被拒絕訪問的子網    192.168.2.0/24      當前主路由表(Routing Table Main,表254):      root@netmonster# ip route list table 254       default via 192.168.254.254 dev eth0 proto static      下面將針對該子網創建一條策略路由規則:      ip rule add from 192.168.2.0/24 priority 5000 prohibit      現在任何從192.168.2.0/24子網發送來的數據報將得到一個類型為3,代碼為13的ICMP消息,同時該數據報將被丟棄。       應該注意的是,在運行任何這些命令都需要發送“ip route flush cache"命令來刷新路由緩沖,否則命令在一段時間以後才會生效,這段時間的長短依賴於路由表結構的大小和負載。       將上面的例子需要的命令放在一起就如下所示:      ip rule del priority 5000   ip rule add from 192.168.2.0/24 priority 5000 prohibit   ip route flush cache      這個命令流通過首先刪除5000號規則來確保當前系統沒有該規則然後再添加新的5000號規則。如果系統本來不存在5000號的規則則會返回一個錯誤信息。然後添加5000號規則並通過清空運行時的路由緩存來重置RPDB,則新規則將馬上產生作用。      多路由表和IP地址      為了完全理解基於策略路由的使用,就需要學會使用Linux多路由表和IP地址,這包括多個方面的知識,下面通過示例來加以說明。      當獲得ip工具,你可能會注意到在發布中有一個名為etc的子目錄,其中有一個名為iproute2的子目錄。應該拷貝該子目錄到/etc目錄下或在/etc目錄下創建iproute2子目錄。該目錄包含用來命名路由表及策略路由結構的其他方面的文件。在該目錄中創建rt_tables文件,其中示例文件一般已經包含了某些內容,並為路由表1提供了示例名。      下面首先編輯該文件來創建若干在下面的示例中使用的表:     # reserved values   #   255   local   254   main   253   default   0    unspec   #   # local   #   1    goodnet1   2    goodnet2   3    badnet1   4    badnet2   5    internet      可以看到通過為路由表命名,就可以使用表數字ID或表名來引用路由表。例如下面兩個命令將對同一個路由表進行操作:     ip route list table 1   ip route list table goodnet1      通過表名可以更好的理解在對哪個路由表進行操作。      例 2:創建多個路由表      如果已經創建了如上所示的rt_table信息,可以通過下面的命令來察看各個路由表的內容:     ip route list table       當然即使沒有定義rt_table文件同樣可以使用數字來引用所有的0-255個路由表,因為它們都是存在的,只是其中大部分沒有路由信息數據罷了。在上面的例子中通過rt_table文件來將表1定義為goodnet1。      下面的例子是向定義的每個路由表都添加一條路由:     ip route add 10.10.10.0/24 via 192.168.1.2 table goodnet1   ip route add 10.10.11.0/24 via 192.168.1.2 table goodnet2   ip route add 10.10.12.0/24 via 192.168.1.2 table badnet1   ip route add 10.10.13.0/24 via 192.168.1.2 table badnet1   ip route add default via 192.168.1.254 table internet      然後再通過ip rouite list talbe 命令就可以察看路由表中的各個路由。      例3:建立多個IP地址      這裡的多個IP地址並不同於IP別名,在Linux2.1及更高版本中已經反對使用":#"的IP別名方式。而應該用新的方式來使用多IP地址。      假設eth0輸出接口應該具有三個不同的IP地址,其中的兩個應該屬於同一個子網,但是應該被獨立地設置,示例同樣說明了在Linux2.2及以上版本的關閉自動路由添加的方法。在Linux2.2及以上版本內核的系統中,當為一個接口賦予一個IP地址時,內核將自動為該IP地址屬於的網絡在路由表中添加一條對應的路由。而由於這裡將為同一個接口賦予屬於同一個子網的兩個不同的IP,所以在添加IP地址時不希望添加路由,否則會造成路由沖突,因此就需要添加該地址為一個主機地址。只需要設置該地址時指定完全主機地址掩碼,然後手工添加必要的路由。       為接口設置如下地址:     192.168.1.1   192.168.1.128   192.168.3.1      在添加192.168.1.0/24的兩個地址時需要關閉自動路由添加,而允許對192.168.3.0/24時允許自動路由添加功能。     ip addr add 192.168.1.1/32 dev eth0   ip addr add 192.168.1.128/32 dev eth0   ip addr add 192.168.3.1/24 dev eth0      這時候如果察看主路由表則會發現內核只為網絡192.168.3.0/24添加了路由表,而沒有為網絡192.168.1.0/24添加路由。      通過ip addr命令可以察看系統的所有IP地址信息:     root@netmonster# ip addr   1: lo: mtu 3924 qdisc noqueue     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00     inet 127.0.0.1/8 brd 127.255.255.255 scope host lo   2: eth0: mtu 1500 qdisc pfifo_fast qlen 100     link/ether 00:00:49:61:32:bc brd ff:ff:ff:ff:ff:ff     inet 192.168.1.1/32 scope global eth0     inet 192.168.1.128/32 scope global eth0     inet 192.168.3.1/24 scope global eth0      下面我們將討論幾個更加復雜的例子。      例 4:多路由表和IP地址      Linux內核路由代碼最強大的特色就是基於策略的路由和使用多地址、多路由表的結合使用。下面的示例討論的是一個充當路由器的連接三個不同的網絡的系統。      參考文章開頭的圖片,可以看到核心系統的外部接口連接了三個外部網絡。每個網絡都有自己的路由器和自己的IP地址空間。但是其中的兩個地址空間是重疊的,因此增加了情況的復雜性。這裡我們設置如下規則的路由表來實現互聯:    從任何內部網絡到Inetent的數據流都是允許的。   從內部網B到網絡A的數據流是允許的。   從內部網A到網絡C的數據流是允許的。   內部網A的地址為33-62的主機允許訪問網絡A。   內部網B的地址為65-78的主機允許訪問網絡C。     首先,配置兩個外部IP地址-在DMZ以太網接口eth0的兩個地址:     ip addr add 10.254.254.2/30 dev eth0   ip addr add 172.17.1.128/24 dev eth0      下一步將討論創建哪些路由表,解決這個問題的最好辦法是想到基於策略的路由能實現根據源地址來決定使用哪個路由表。策略規則具有劃分內部網絡的能力,因此首先可以在路由表中添加基於目的的路由,在示例中我們將使用前面創建的新的路由表。      當在路由表中添加路由時下面的方法有助於澄清應該采取的步驟。假設你配置的是只有兩個接口的路由器,外接口直接連接Interet出口路由器,而內接口直接連接內部網絡。配置這樣的路由器是非常簡單的,為了說明我們這裡在表1-goodnet1這個路由表進行操作:     ip route add 10.10.0.0/16 via 10.254.254.2 table goodnet1 proto static   ip route add default via 172.17.1.254 table goodnet1 proto static      對於goodnet2進行配置則是:     ip route add 172.18.0.0/16 via 172.17.1.1 table goodnet2 proto static   ip route add default via 172.17.1.254 table goodnet2 proto static      可以看到對三個目標網絡只需要兩個路由表,這裡對於連接Internet的默認路由在兩個表中都進行了設置。為什麼不將默認路由存放在第三個路由表中呢?首先應該考慮到規則和路由表之間的交互,而且規則是實現對基於策略路由的定義。多條規則可以指向同一個路由表。然而,一旦進入某個路由表以後,則只能是匹配一條路由或返回一條路由鏈。如果匹配到一條規則則就認為你已經擁有一條正確的策略匹配,則該規則指向的路由表包含了該數據報所有的路由可能。      如果有三個路由表,則需要添加一條規則來察看數據報目的。而檢查數據報目的地址是標准路由的功能。為什麼要對每種源、目的的組合都需要一個規則呢?通過使用路由表,可以實現定義盡量少的規則來達到目的。當然 系統的靈活性允許通過多條方法來實現這樣的路由。可以根據在自己的喜好來決定那種方案最適合:      ip rule add from 192.168.1.32/27 to 172.18.0.0/16 pref 15000 table goodnet1   ip rule add from 192.168.2.64/28 to 10.10.0.0/16 pref 15001 table goodnet2   ip rule add from 192.168.1.0/24 pref 15002 table goodnet1   ip rule add from 192.168.2.0/24 pref 15003 table goodnet2      上面的例子中使用了優先級參數設定來定義數據報匹配規則的順序。現在來看看當一個數據報從內部網絡經過路由系統時會發生什麼情況。首先,它會通過優先級為0的規則檢查;隨後會遇到優先級為15000的規則,若匹配則會被goodnet1這個路由表進行操作,否則將會分別經過15001、15002、15003的規則。它肯定會被15000-15003幾個規則中的一個所匹配。       下面為了說明定義路由結構的靈活性,我們將從另外一個角度來解決這個問題。Linux路由器的詳細情況如下:     eth0 - DMZ ethernet - addresses: 10.254.254.2/30, 172.17.1.128/24   eth1 - Internal A - addresses: 192.168.1.254/24   eth2 - Internal B - addresses: 192.168.2.254/24      首先假設重新開始,將重新定義路由和規則,首先編輯/etc/iproute2/rt_tables:      # reserved values   #   255   local   254   main   253   default   0    unspec   #   # Local Tables   #   1    int1   2    int2      創建路由和規則:     ip route add 10.10.0.0/16 via 10.254.254.1 table int1 proto static   ip route add throw 0/0 table int1 proto static   ip route add 172.18.0.0/16 via 172.17.1.1 table int2 proto static   ip route add throw 0/0 table int2 proto static   ip route add 0/0 via 172.17.1.254 table main proto static   ip rule add pref 15000 table int1 iif eth1   ip rule add pref 15001 table int2 iif eth2   ip rule add pref 15002 to 10.10.0.0/16 table int1   ip rule add pref 15003 to 172.18.0.0/16 table int2      這些路由和規實施和前面示例一樣的操作(仔細研究這些規則和路由並理解它們)       使用ipchains實現高級策略路由      在指定策略規則時可以使用的一個選項就是允許通過fwmark值來匹配某個規則。fwmark是一個數字標簽,數據報過濾工具ipchains能將fwmark值附加給某個數據報。如果你對ipchains並不是很熟悉,你需要首先閱讀ipchains-howto.      例 5:簡單基於fwmard的策略路由      首先從一個簡單的例子開始-利用上面示例中的多路由表,希望實現來自內部網B的、目的端口為80的數據發送到Internet,但是來自內部網A的、目的端口為80的數據則被禁止。首先清空這些路由表:     ip route flush table goodnet1   ip route flush table goodnet2     ip route flush table badnet1     ip route flush table badnet2     ip route flush table internet     ip route flush cache      而目前刪除策略規則的方法就是將其一一列出來然後將其手工刪除,也就是首先通過ip rule list命令將策略規則列出來然後使用ip rule del priority <#>將其刪除。但這裡假設當前沒有任何規則並且路由表也是空的。      為了使用fwmark標記,首先應該指定希望使用ipchains標記的數據報,然後使用標記值來指定一條策略規則來處理該數據報。應該設定ipchians自動將十進制的標記轉化為十六進制。ip rule希望輸入為一個十六值。      首先配置ipchains規則使用合適的值標記輸入數據報。假設當前沒有其他防火牆規則:     ipchains -I input -p tcp -s 192.168.2.0/24 -d 0/0 80 -m 2   ipchains -I input -p tcp -s 192.168.1.0/24 -d 0/0 80 -m 16      現在設立策略規則,在上面為內部網A的標記值為十機制的16,下面定義相關的策略(應該注意到策略定義中使用的是十六進制,因此為10):     ip rule add fwmark 2 table goodnet1   ip rule add fwmark 10 prohibit      最後為路由表goodnet1定義如下的路由:     ip route add default via 172.17.1.254 table goodnet1      關於策略路由的一個常見問題是策略路由和IP偽裝之間如何交互,這裡我們不對該問題進行深入研究但是通過一個快速的示例來加以說明。需要注意的是在轉發鏈之前對路由表進行查詢。這意味著如果使用IP偽裝,則路由選擇器返回的任何源地址都將被作為進行IP偽裝的地址。      例6:朵IP地址的IP偽裝      使用上面的網絡配置,我這裡將對到三個網絡的連接進行偽裝處理,希望從系統中得到如下的輸出:      從內部網A到網絡C的數據報被偽裝為10.254.254.2   從內部網絡B到網絡A的數據報被偽裝為172.17.1.2   內部網到互聯網的數據報都被偽裝為172.17.1.128     eth0配置有如下地址:     10.254.254.2/30   172.17.1.128/24      因此為了滿足條件2,給eth0添加地址:     ip addr add 172.17.1.2/32 dev eth0      假設系統被設置為對所有的輸出數據報都進行IP偽裝。首先清空舊的策略規則,然後創建新的規則如下:     ip route add 10.10.0.0/16 via 10.254.254.2 src 10.254.254.2      table goodnet1 proto static   ip route add default via 172.17.1.254 src 172.17.1.128      table goodnet1 proto static   ip route add 172.18.0.0/16 via 172.17.1.1 src 172.17.1.2      table goodnet2 proto static   ip route add default via 172.17.1.254 src 172.17.1.128      table goodnet2 proto static   ip rule add from 192.168.1.0/24 pref 15000 table goodnet2   ip rule add from 192.168.2.0/24 pref 15001 table goodnet1      例7:綜合實例      假設例6中的路由、規則和地址仍然在起作用,我希望實現下面的需求:    Internal A Hosts 33-62 to Network A Masq as 172.17.1.3   Internal A Hosts 65-78 to tcp port 80 on Network A Masq as 172.17.1.4   Internal B Hosts 33-62 to tcp port 80 on Network A Deny Access   Internal B Hosts 65-78 to tcp port 80 on Network C Masq as 10.254.254.2     應該記得我們仍然允許例6中的連接性,下面就是解決方案:     ip addr add 172.17.1.3/32 dev eth0   ip addr add 172.17.1.4/32 dev eth0   ip route del default table goodnet1   ip route del default table goodnet2   ip route add throw 0/0 table goodnet1 proto static   ip route add throw 0/0 table goodnet2 proto static   ip route add default via 172.17.1.254 src 172.17.1.128      table internet proto static   ip route add 172.18.0.0/16 via 172.17.1.1 src 172.17.1.3      table badnet1 proto static   ip route add 172.18.0.0/16 via 172.17.1.1 src 172.17.1.4      table badnet2 proto static   ip rule add from 192.168.1.32/27 to 172.18.0.0/16 pref 14999 table badnet1   ip rule add fwmark 1 pref 14998 table badnet2   ip rule add fwmark 2 pref 14997 table goodnet1   ip rule add fwmark 3 pref 14996 blackhole   ip rule add pref 15003 table internet   ipchains -I input -p tcp -s 192.168.1.64/28 -d 172.18.0.0/16 80 -m 1   ipchains -I input -p tcp -s 192.168.2.64/28 -d 10.10.0.0/16 80 -m 2   ipchains -I input -p tcp -s 192.168.2.32/27 -d 172.18.0.0/16 80 -m 3      其實有很多的有效方法,但是雖然這裡使用名為badnet1和badnet2的表,但是名字是沒有實際意義的,只是用來引用表3和表4的符號。      總結      希望你通過該文章能享受Linux2.2的強大路由功能,它提供的路由功能是很多路由器產品都是難以匹敵的, 如果考慮到它的免費性,它的性能價格比更是沒有任何產品可以相比。例如例7中的例子可以很好的運行在只有16M內存的486/33的機器上。   




 



Copyright © Linux教程網 All Rights Reserved