2020年2月20日 星期四

arp_ignore 和 arp_filter

From:http://huntxu.github.io/2015-12-24-arp-filter-vs-arp-ignore.html


arp_ignore 和 arp_filter

24 Dec 2015
先說結論好了
  1. arp_filter有個表哥叫做rp_filter,這裏的rpReserve Path的意思,其實就是用來檢查返回的包是否會從相對應的到來的包使用相同的網絡接口出去。它們的區別只是層次不同
  2. arp_ignore 則是內核用來確定是否應該回覆從該端口收到的ARP請求的
  3. 這兩個判斷都在內核中的net/ipv4/arp.c
故事是因爲有個同事在一個機器上用libvirt搭建了幾臺虛擬機之後使用橋接連接這幾臺機器,並且使用自動部署工具去部署這幾臺機器。結果發現其中有一臺機器的一個網卡沒有成功得到預期的地址。調查之後發現那臺機器在配置該地址之前使用了arping -D去檢查是否與其他機器已有的地址相互衝突了,剛巧該地址和宿主機之上的另外一個網卡地址相同,於是宿主機上橋接虛擬機網絡的網卡,便響應了那個ARP請求,導致配置失敗。
一開始我也很奇怪,爲什麼明明宿主機上橋接着虛擬機網絡的網卡並不擁有那個目標地址但卻會回覆,而更奇怪的是,虛擬機中使用arping不加-D參數,也收不到回覆。所以經過一番搜索與測試驗證,才大致搞明白了其中的原因。
首先,在內核文檔中有這樣一段對arp_filter參數的描述:
0 - (default) The kernel can respond to arp requests with addresses
from other interfaces. This may seem wrong but it usually makes
sense, because it increases the chance of successful communication.
IP addresses are owned by the complete host on Linux, not by
particular interfaces. Only for more complex setups like load-
balancing, does this behaviour cause problems.
內核認爲一個IP地址是屬於整個主機的,而非某個特定的端口,所以默認情況下,每個端口都會回覆目標是其他端口的IP地址的ARP請求。
查看了機器之後發現這一項爲默認值0,但是又一個疑問發生了,爲什麼使用arping不帶-D參數就無法收到返回呢?答案是rp_filter做了過濾,默認回應的包不從收到的端口出去,所以並不回覆。
那麼接下來又有一個問題,爲什麼帶了-D參數就收的到回覆呢?原因是,如果使用arping -D的話,發出的請求包的原地址是設置爲0.0.0.0的,這點可以參考RFC2131中的4.4.1一段。然後來看代碼:
    /* Special case: IPv4 duplicate address detection packet (RFC2131) */
    if (sip == 0) {
            if (arp->ar_op == htons(ARPOP_REQUEST) &&
                inet_addr_type_dev_table(net, dev, tip) == RTN_LOCAL &&
                !arp_ignore(in_dev, sip, tip))
                    arp_send_dst(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip,
                                    sha, dev->dev_addr, sha, reply_dst);
            goto out;
    }
當請求包的地址爲0.0.0.0的時候,內核只照顧arp_ignore這個選項,而不去管arp_filter選項的內容,也不去管rp_filter的內容。
下面看兩個場景,加深一下對這幾個參數的印象:
  1. 主機上兩個接口,地址分別處於不同的子網之中
    • 這種情況不會引起混亂
    • 從哪個端口進來的ARP請求,一般來說請求的源地址也是那個子網之中的地址,因此回覆包也會從該端口出去,所以能通過rp_filter以及arp_filter的驗證
    • 這種情況下的回覆只需要考慮arp_ignore的影響
  2. 主機上兩個接口,地址處於相同的子網之中
    • 容易引起混亂的情況
    • 兩個端口進來的ARP請求,基本上源地址是同一個子網,因此回覆的包只會從ifindex較小(猜測,未驗證)的端口發送出去,因此從其中一個端口進來的請求有可能無法通過rp_filter以及arp_filter的驗證
    • 同樣需要考慮arp_ignore的影響,對於上面說的收到無法通過rp_filter以及arp_filter驗證的請求包的端口,除非請求的源地址爲0.0.0.0,否則便根本不會回覆,而另一端口收到的則正常,而且對兩個接口上所設置的地址,都能夠通過上述的驗證
    • 要想讓兩個端口在同一子網中互不干擾,各自使用各自的地址並各自對請求包進行回覆,則需要使用策略路由,並且將arp_filterrp_filter打開,arp_ignore正確設置
關於這些選項的具體設置值的意義,可以參考內核文檔,這裏就不複製粘貼進來加長篇幅了。總之,在能夠進行規劃的情況下,還是儘量避免容易引起混亂的情況爲好。

2019年3月25日 星期一

VXLAN vs VLAN

from:https://zhuanlan.zhihu.com/p/36165475


VXLAN(Virtual eXtensible Local Area Network)或許是目前最熱門的網絡虛擬化技術。
網絡虛擬化是指在一套物理網絡設備上虛擬出多個二層網絡。VXLAN由RFC7348定義,這是2014年定稿的一個協議,VXLAN協議將Ethernet幀封裝在UDP內,再加上8個字節的VXLAN header,用來標識不同的二層網絡。

同樣是網絡虛擬化技術的VLAN(Virtual Local Network)在1998年就提出了第一稿,並且得到廣泛的應用,VLAN直接在Ethernet幀的頭部加上4個字節的VLAN Tag,用來標識不同的二層網絡。VLAN已經在大部分的網絡設備和操作系統中得到了支持,它處理起來也比較簡單,在讀取Ethernet數據的時候,只需要根據EtherType相應的偏移4個字節就行。相比之下,VXLAN因為提出的較晚,在設備上的支持率不如VLAN,而且,VXLAN數據的封裝解封裝,要比VLAN複雜的多。看起來沒理由VXLAN搶占VLAN的地位,但是現實卻不是如此,那究竟是什麼原因導致的呢?

VXLAN協議

我們先來看看VXLAN協議,前面說過,VXLAN是將Ethernet Frame封裝在UDP包裡面,具體的協議格式如下。
除了常規的各層的header之外,VXLAN協議定義了8個字節的VXLAN Header。其中的24bit用來標識不同的二層網絡,這樣總共可以標識1600多萬個不同的二層網絡。一般的傳輸層端口號用來標識進程或者應用,但是在VXLAN協議裡面的,Ethernet Frame封裝在UDP裡面,UDP的source port被用來在ECMP或者LACP做負載均衡;destination port被用來標識VXLAN數據,IANA(Internet Assigned Numbers Authority)分配給VXLAN的端口號是4789。VXLAN數據是經過VTEP(VXLAN Tunnel EndPoint)封裝和解封裝的,相應的VXLAN數據的外層IP地址就是VTEP的IP地址。最外層的MAC地址用來實現VTEP之間的數據傳遞。
VXLAN與VLAN的最大區別在於,VLAN只是修改了原始的Ethernet Header,但是整個網絡數據包還是原來那個數據包,而VXLAN是將原始的Ethernet Frame隱藏在UDP數據裡面。經過VTEP封裝之後,在網絡線路上看起來只有VTEP之間的UDP數據傳遞,原始的網絡數據包被掩蓋了。
VXLAN並不是憑空出現,這種在UDP裡面封裝網絡數據的做法,在VXLAN之前就已經存在,例如OTV(Overlay Transport Virtualization)和LISP(Locator/ID Separation Protocol )。

為什麼要VXLAN?

相比VLAN,VXLAN顯得複雜很多。再加上VLAN的先發優勢,已經得到了廣泛的支持。那為什麼還要VXLAN?
VLAN ID數量限制
--
首先是VLAN能支持的二層網絡數量有限。VLAN Tag總共4個字節,其中有12bit用來標識不同的二層網絡,這樣總共是4000多個。而VXLAN header有8個字節,有24bit用來標識不同的二層網絡,這樣總共是1600多萬個。這或許是知名度最高的一條原因。但這是最根本的原因嗎?VLAN自身也有一些相關的協議,其中QinQ(IEEE 802.1 ad)定義在Ethernet頭部加上2個VLAN Tag,這樣總共也可以由12+12=24bit的數據用來標識不同的二層網絡。如果僅僅是因為能支持的二層網絡數量有限,只需要在現有的VLAN設備上做一些改動,直接用QinQ就好了。所以,選用VXLAN一定還有其他原因。
TOR交換機MAC地址表限制
--
數據中心的虛擬化給網絡設備帶來的最直接影響就是:之前TOR(Top Of Rack)交換機的一個端口連接一個物理主機對應一個MAC地址,但現在交換機的一個端口雖然還是連接一個物理主機但是可能進而連接幾十個甚至上百個虛擬機和相應數量的MAC地址。傳統交換機是根據MAC地址表實現二層轉發。如下圖所示,交換機在收到一個數據幀之後,根據VLAN和目的MAC地址,查找到相應的交換機端口,再將數據幀從相應的端口發出。
這個MAC地址表是通過交換機的flood-learn學習並記錄在交換機的內存。交換機的內存比較寶貴,所以MAC地址表的大小通常是有限的。現在因為虛擬化,整個數據中心的MAC地址多了幾十倍,那相應的交換機裡面的MAC地址表也需要擴大幾十倍。如果交換機不支持這麼大的MAC地址表,那麼就會導致MAC地址表溢出。溢出之後,交換機不能將新的MAC地址學習到自己的MAC地址表。如果交換機收到這些MAC地址的數據幀,因為不能通過查表轉發,會flood到所有的端口。這不但增加了交換機的負擔,還增加了網絡中其他設備的負擔。為了避免這個問題,可以用一些更大容量的交換機,但是相應的成本也要上升,而且還不能從根本上解決這個問題。
如果使用VXLAN,虛擬機的Ethernet Frame被VTEP封裝在UDP裡面,一個VTEP可以被一個物理主機上的所有虛擬機共用。從交換機的角度,交換機看到的是VTEP之間在傳遞UDP數據。通常,一個物理主機對應一個VTEP,所以交換機的MAC地址表,只需要記錄與物理主機數量相當條目就可以了,虛擬化帶來的MAC地址表暴增的問題也不存在了。這是VXLAN能解決的,而現有的VLAN沒有辦法迴避的問題。
靈活的虛機部署和部署
--
採用VLAN網絡的虛擬環境,不存在overlay網絡。虛擬機的網絡數據,被打上VLAN Tag之後,直接在物理網絡上傳輸,與物理網絡上的VLAN是融合在一起的。這樣的好處是虛擬機能直接訪問到物理網絡的設備,但是壞處是,虛擬網絡現在不能打破物理網絡的限制。比如,如果要在VLAN 100部署虛擬機,那隻能在支持VLAN 100的物理設備上部署虛機。通常不同的VLAN網絡,會被分配不同的IP地址段,通過路由器或者其他的三層設備連接在一起。設想我有下面一個環境,​​紫色區域和綠色區域分別對應不同的VLAN網絡,紫色區域裡面每個服務器已經有10個虛機,綠色區域每個服務器只有2個虛機,紫色區域雖然服務器數量更多,但是總的負擔已經夠重了。現在因為業務的需求,我們還需要向紫色網絡裡面部署虛機,因為VLAN網絡無法打破物理二層網絡的限制,虛機還是只能部署在紫色區域,這明顯不合理。
另一方面,就算不部署新的虛擬機,只是對現有的部署做一個優化,將部分虛擬機從紫色區域遷移到綠色區域,因為無法打破物理二層網絡的限制,這也是不可行的。因為業務肯定不是平均分配的,那如果採用VLAN網絡,極有可能會導致數據中心的利用率分佈不均勻。
VLAN其實有自己的解決辦法,如果將所有的交換機Trunk連接起來,那在物理上沒有明確的區域區分。但是這樣就產生了一個大的二層,相應的BUM(Broadcast,Unknown Unicast,Multicast)和交換機MAC地址表的問題也會隨之產生。
如果使用VXLAN呢?因為VXLAN通過UDP傳輸Ethernet Frame,那相應的可以在一個L3網絡上,傳遞L2的數據。又或者用官方的說法,在一個L3網絡上構建了L2網絡。物理網絡的二層邊界還存在,但是現在虛機的網絡數據在三層網絡傳輸,可以跨越物理二層網絡的限制。
不管物理網絡的二層還是三層,虛擬機現在已經感知不到了。通過VXLAN的封裝,虛擬機現在走的是一套獨立於物理網絡(underlay network)的overlay network。這樣的話,在物理網絡上,就不必把所有的交換機Trunk連起來,還是可以保持一個個小的L2 Pod。但是同時,虛擬機的部署和遷移,又不用受物理網絡的限制,整個數據中心可以保持一個平均的利用率。這是另外一個VXLAN能解決,但是VLAN無法迴避的問題。
更好的利用多條網絡鏈路
--
VLAN協議使用STP(Spanning Tree Protocol)來管理多條線路,STP根據優先級和cost,只會選出一條線路來工作,這樣可以避免數據傳遞的環路。這種主備(active-passive)的模式,比只連接一條線路肯定是有優勢,但是對於用戶來說,相當於花了N倍的錢,卻只用到了1倍的服務。當網絡流量較大的時,也不能通過增加線路來提升性能。而VXLAN因為是通過UDP封裝,在三層網絡上傳輸。雖然傳遞的還是二層的Ethernet Frame,但是VXLAN可以利用一些基於三層的協議來實現多條線路共同工作(active-active),以實現負載均衡,例如ECMP,LACP。現在對於用戶來說,花了N倍的錢,也用到了N倍的服務。當網絡流量較大時,現在可以通過增加線路來減輕現有線路的負擔。這在提升數據中心網絡性能,尤其是東西向流量的性能時,尤其重要。這是VXLAN相比VLAN,能帶來的另一個好處。

最後

所以,儘管VXLAN要復雜一些,提出的晚一些,普及率也要低一些,但是隨著數據中心規模的發展和虛擬化的普及,VXLAN逐漸成為構建數據中心網絡的趨勢。
不過理智點看,VXLAN有這麼多優點,在可以預見的未來,還是不能完全替代VLAN。首先VXLAN是一種overlay網絡,不能獨立存在,必須依賴underlay網絡,而在構建underlay網絡時,還是需要藉助VLAN。其次,這裡介紹的VXLAN的優勢,都是在大規模環境下,如果你的數據中心的規模,不論虛機還是物理的,就百十台的樣子,那直接用VLAN也可以了,沒必要上VXLAN。
VXLAN最多是在構建數據中心時的一個選項,而不是唯一的選項。套用馬斯洛的“工具法則”:當你只有一個錘子時,任何東西看起來都像是個釘子。在設計數據中心網絡時,也應該避免用一種方法解決所有問題,VXLAN,VLAN,BGP,EVPN,OpenStack應該綜合考慮。

2018年12月27日 星期四

什麼是MPLS

From:http://eservice.seed.net.tw/class/class0801c.html
多重通訊協定標籤交換傳輸(Multi-Protocol Label Switching)是由IETF 所發展出來的Network Standard。它是實現寬頻網際網路最熱門的技術;其目的是要提供一個更具彈性、擴充性及效率更高的IP層交換技術。
MPLS 是一種整合了標籤交換架構與網路層的路由機制的技術,最基本的概念是將進入MPLS Network 的封包(Packet)配置一個固定長度的標籤(Label),在MPLS Network中Packet會根據標籤(Label) 做Forwarding , 由Label來決定Packet在網路上的路徑,不會再看 Layer 3的 IP Header(標頭)。
傳統IP Network 的運作方式
Packet在一般的IP Network傳遞時,路由器的運作是以所謂的"Store and Forward"的程序來做Packet路由的選擇及轉送,所以當路由器收到一個Packet時,會先儲存Packet 、分析路由、轉送Packet 到下一個適當的路由器,而當此路由器又收到下一個Packet 要傳送到相同的目的地時,它必須重覆執行相同的程序(儲存、分析、轉送),這樣是很沒有效率的而且會耗用路由器大量的CPU處理能力及記憶體空間,此外傳統的路由器是以軟體的處理方式轉送IP 封包,而MPLS的技術則是引用與ATM交換技術類似的標籤交換(Label Switching)技術,簡化了路由器的轉送功能直接利用Switching Fabric以線上速度(Line Speed)來轉送封包(Packet)到達目的地。
MPLS Label 的Format及插入Packet的位置
Label是一個4Bytes、固定長度、locally-significant identifier類似在ATM網路中VPI(Virtual Path Identifier)/VCI(Virtual Circuit Identifier)或是Frame-Relay網路中的DLCI(Data Link Circuit Identifier),Label是被插入於Packet的第二層資料鏈結層(data link layer)與第三層網路層(network layer)Header之間。
MPLS Network 的組成
MPLS 網路是由多個具有標籤交換能力的路由器LSR(Label Switch Router)互相連結所組成,根據在MPLS網路內扮演角色的不同LSR可以分為三種類型:
(1) Ingress LSR:負責將進入MPLS網路的IP Packet貼上標籤(Push Label)
(2) Core LSR:LSR則位於MPLS網路的核心,負責做標籤轉換(Label Swap)
(3) Egress LSR:當封包要離開MPLS網路到一般IP網路時,負責去除標籤( Pop Label)。

Label Assignment and Distribution的過程
  1. LSR Routing Table的建立:在MPLS網路中所有的LSR利用routing protocol來交換路由資訊,建立自己的IP Routing Table,並根據Routing Table 建立自己的FIB(Forwarding Information Base),此時的FIB中並沒有Label的資訊。
  2. LSR Allocating Label過程: 當LSR路由器開始啟動MPLS功能時,會根據由IGP(如RIP、OSPF)學來的路由表(Routing Table)內容,對於使用相同處理方式、相同path、到達相同目的地IP subnet的Routing entry 做彙整(aggregation)及分類後Assign Label。
  3. LSR 初步建立自己的LIB及LFIB:將前面步驟Allocating 的local Label資訊儲存於LIB(Label Information Base)和LFIB(Label Forwarding Information Base)中,此時的LFIB中只有local Label 的資訊並沒有outgoing Label 的資訊。
  4. LSR Label Distribution過程:LSR將他Local assign的Label資訊傳送(Distribution)給相鄰的LSR,不論這相鄰的LSR是local LSR的downstream或upstream 都會傳送,而Label Distribution 靠的是相鄰的LSR間要執行LDP(Label Distribution Protocol)的協定,來互相交換彼此的Label資訊。另外談到LDP 的特性,MPLS Device 會send/receive LDP,LDP 透過Discovery 去和Neighbor溝通對方是否有啟動MPLS及交換Label information,而LDP是用UDP protocol去discovery neighbor,並利用 TCP 去去交換彼此Label information。
  5. LSR收到相鄰LSR送來的Lable資訊做資訊的彙整過程:最後每個LSR 根據接收到相鄰LSR送來的Label 資訊後,新增這些Label資訊於自己的LIB中,並根據routing table得到的最佳路徑,獲知到某網段的Next-hop LSR 所送來的Label資訊,插入到LFIB的outgoing Label資料結構中。
Packet在MPLS網路中傳送的過程
  1. Ingress LSR(Router A):IP Packet 進入MPLS網路的第一顆LSR路由器稱為Ingress LSR,當IP Packet 進入Ingress LSR 首先會查看Packet中的Destination IP address,並且在FIB中lookup 是否有符合的IP network ,如果有則進一步查看FIB中相對應的Label欄位其值為何?(例如:IP =X ,Label=25 ),當Packet從Ingress LSR 送出時,會在此Packet中打上Label=25的標示,再傳送出去。
  2. Core LSR (Router B):當帶有Label=25的Packet傳到Router B時,Router B會查看(lookup)他的LFIB的資料,看看是否有Inbound Label=25的entry,如果有則再查看此entry中Outgoing Label的欄位值為何?(例如 Outgoing Label=47),所以Packet中的Label快速的被置換(Label=25 aLabel=47)並往下一個節點傳送出去。
  3. Egress LSR(Router C):當帶有Label=47的Packet傳到Router C時,Router C會查看(lookup)他的LFIB的資料,看看是否有Inbound Label=47的entry,如果有則再查看此entry中Outgoing Label的欄位值為何?(例如 Outgoing Label=Pop),所以Packet中的Label被移除,此時已離開MPLS網路再進入到IP的網路中,因此重新查看Packet中的Destination IP address為何?並查看其FIB以決定Packet要傳送的下一個節點 。
在MPLS網路中Egress LSR double lookup的問題
由於Egress LSR不但要查看LFIB中的資料以便移除Packet 中的Label,而且還要查看FIB中的資料以決定將Packet往IP網路的下一個節點傳送,這樣的作法會使Egress LSR 的負擔太重,而且對傳送有Label的封包也不是最有效的方式。
Penultimate Hop Popping
所以解決的方式就是在原來Egress LSR前一個節點就把Label移除,最後一顆Router 只要做IP lookup 就好了,此種運作方式稱為Penultimate Hop Popping。
結語
本篇文章從一開始介紹傳統路由器在IP 路由傳送封包的運作缺點及描述發展MPLS技術的優勢,並且說明整個MPLS 技術的運作原理,從MPLS Label的format介紹及Label在封包標頭位置的解說,到整個MPLS網路中各個不同角色LSR的運作方式,在其中更詳細的探討Label 如何被Assignment及 相鄰LSR之間如何交換彼此的Label Information的過程,另外更舉例說明封包在MPLS網路中從Push(加上)Label,一直到離開MPLS網路前Pop(去除)Label的詳細過程,最後則探討為何封包在離開MPLS網路的前一個節點(Hop)就要先Pop(去除)Label的原因。

2018年9月20日 星期四

用ipset配置linux防火牆

From:http://blog.chinaunix.net/uid-21706718-id-3561951.html
iptables是在linux內核裡配置防火牆規則的用戶空間工具,它實際上是netfilter框架的一部分.可能因為iptables是netfilter框架裡最常見的部分,所以這個框架通常被稱為iptables,iptables是linux從2.4版本引入的防火牆解決方案. 


ipset是iptables的擴展,它允許你創建匹配整個地址sets(地址集合)的規則。而不像普通的iptables鍊是線性的存儲和過濾,ip集合存儲在帶索引的數據結構中,這種結構即時集合比較大也可以進行高效的查找. 

除了一些常用的情況,比如阻止一些危險主機訪問本機,從而減少系統資源佔用或網絡擁塞,IPsets也具備一些新防火牆設計方法,並簡化了配置. 

在本文中,在快速的討論ipsets的安裝要求後,我會花一點時間來介紹iptables的核心機制和基本概念.然後我會介紹ipset的使用方法和語法,並且演示ipset如何與iptables結合來完成各種不同的配置。最後,我會提供一些細節和較高級的例子來演示如何解決現實中的問題。

ipset比傳統的iptables擁有顯著的性能提升和擴展特性,比如將單個防火牆規則通過一次配置應用到整個主機所在的組和網絡。

由於ipset只是iptables的擴展,所以也會對iptables進行描述。

在許多的linux發布中ipset是一個簡單的安裝包,大家可以通過自己的linux發行版提供的包管理工具進行安裝。

需要理解的重點時,同iptables一樣,ipset是由用戶空間的工具和內核空間的模塊兩部分組成,所以你需要將這兩部分都準備好。你也需要"ipset-aware"這個iptables模塊,這個模塊用來增加rules that match against sets。(……)

首先我們使用自己的linux發行版的包管理工具對ipset進行搜索。在ubuntu上安裝需要安裝ipset和xtables-addons-source包,然後,運行module-assistant auto-install xtables-addons,等待大約30秒後ipset就可以使用了。

如果你的linux發行版沒有被支持,那就需要根據ipset首頁中的安裝步驟構建源碼並對內核打補丁。

這篇文章中使用ipset v4.3和iptables v1.4.9。

iptables概述

簡單來講,iptables防火牆配置由規則鏈的集合組成,每一個鏈包含一個規則。一個數據包,在各個處理階段,內核商量合適的規則來決定數據報的命運。

規則鏈按照順序進行匹配,基於數據包的流向(remote-to-local, remote-to-remote or local-to-remote)和當前所處的處理階段(before or after "routing")。參考圖1。

當需要匹配規則鏈時,數據包需要與鏈中的每個規則按照順序進行比對,直道找到匹配的規則。一旦找到了匹配的規則,目標規則就會被調用。如果最後一個規則與數據包也不匹配,就會使用默認規則。
一個規則鏈就是許多規則按順序排列組成,一個規則就是match/target的組合。一個簡單的match例子是“TCP目標端口為80”。target的例子是“接受這個包”。target同樣可以將數據包重定向到其他的用戶自定義的鏈,用戶自定義鏈提供了一些機制,包括組合和細分規則,將多個鏈級聯來完成一個功能。
每一個用來定義規則的iptables命令,不管是用於簡單的規則還是複雜的規則,都有三個基本的部分組成,包括指定table/chain (and order), match和target。

Figure 2.解析iptables命令
配置所有的這些選項,創建一個完整得防火牆,你需要按照特定的順序運行一系列的iptables命令。
iptables非常強大並且可擴展。除了許多內部特性,iptables提供了擴展match和target的API。
ipset
ipset是iptables的match擴展。如果要使用它,需要使用ipset命令行工具創建一個集合併指定一個唯一的集和名,然後在iptables規則的match部分分別索引這些集合。
一個集合是一個方便有效快速查詢的地址列表。
下面有兩個常見的iptables命令,這兩個命令阻止從1.1.1.1和2.2.2.2進入主機的數據包:
iptables -A INPUT -s 1.1.1.1 -j DROP
iptables -A INPUT -s 2.2.2.2 -j DROP 
match部分語法-s 1.1.1.1表示“匹配源地址是1.1.1.1的數據包”。
下面的ipset/iptables命令同樣可以達到上面的目的:
ipset -N myset iphash 
ipset -A myset 1.1.1.1 
ipset -A myset 2.2.2.2 
iptables -A INPUT -m set --set myset src -j DROP 
上面的ipset命令創建了一個包含兩個地址(1.1.1.1 and 2.2.2.2)的集合(myset of type iphash)。
然後iptables命令通過-m set --set myset src這個match選項使用這個集合,這個匹配規則的意思是“匹配源地址包含在集合myset中的數據包” 
src表示源地址,dst表示目標地址。如果同時使用src和dst表示既要匹配源地址又要匹配目的地址。
在第二個例子裡,只需要一個iptables命令,不管集合裡有多少ip地址需要添加。雖然這個例子裡只使用了兩個地址,但是你可以依據這個例子簡單的定義1000個地址,並且仍然只需要一條iptables語句。而如果使用第一個例子的方法,不使用ipset,就需要1000條iptables規則。
Set Types
每一個集合都是特定類型的,它不但定義了什麼類型的值可以儲存在裡面(IP addresses, networks, ports and so on),而且定義瞭如何匹配數據包(換言之,數據包的那一部分需要被檢查和如何檢查)。除了一些最通用的集合類型,比如檢查ip地址,也提供了一些其他的集合類型,比如檢查端口,地址和端口同時檢查,mac地址和ip地址同時檢查等。
每一種集合類型都有自己的規則,這些規則表示集合的類型,範圍,它包含的值得分佈。不同的集合類型使用不同的類型索引,並且在不同的情況下被優化。需要根據不同的現實情況選擇集合類型。
最靈活的集合類型是iphash,它可以存儲任意的ip地址和nethash(IP/mask)。請參考ipset的man手冊來了解所有的集合類型。
setlist是一個特別的集合類型,它允許組織多個集合到一個集合裡面。比如你需要一個單獨的集合既包含ip地址又包含網絡信息。
Advantages of ipset 
除了性能優勢,一些情況下ipset允許更直接的配置方法。
如果你想定義一個防火牆環境,該環境不會處理來自1.1.1.1和2.2.2.2的包,並且處理過程包含在mychain中,注意下面的方法是無效的:
iptables -A INPUT -s ! 1.1.1.1 -g mychain 
iptables -A INPUT -s ! 2.2.2.2 -g mychain 
如果數據包來自1.1.1.1,它匹配第一條規則失敗,但是匹配第二條規則時會成功。如果數據包來自2.2.2.2,匹配第一個規則就會成功。
雖然有有一些其它的方法可以不適用ipset就能達到指定的要求,但是ipset是最直接了當的。
ipset -N myset iphash 
ipset -A myset 1.1.1.1 
ipset -A myset 2.2.2.2 
iptables -A INPUT -m set ! --set myset src -g mychain 
用上面的方法,如果數據包來自1.1.1.1,它不會匹配規則(because the source address 1.1.1.1 does match the set myset)。如果數據包來自2.2.2.2,它也不會匹配規則。
這只是一個簡單的例子,它說明在一個規則裡匹配完整條件的基本優點。其他方面,每個iptables規則與其它規則是獨立的,並且將規則邏輯的連接起來是比較難的,特別當它包含混合了正常和反向測試時。ipset只是在這些情況下使配置變簡單。
ipset的另一個優勢是集合可以動態的修改,即使iptables的規則正在使用這個集合。添加/修改/刪除接口使用很簡單並且是順序無關的。另一方面,在iptables裡每一條規則都比較複雜,並且規則的順序也是很重要的元素,所以修改內部規則很困難並且會存在潛在問題。

Excluding WAN, VPN and Other Routed Networks from the NAT—the Right Way

Outbound NAT (SNAT或IP偽裝)允許私有局域網內的主機訪問internet.iptables NAT規則匹配私網內訪問internat的包,並用網關地址替換包的源地址(使數據包看起來像是從網關發送的,從而隱藏網關後面的主機)。

NAT自動跟踪活動的連接,所以它能將返回的包發送給正確的內網主機(通過將數據包的目的地址修改為內部主機地址)。

下面是一個簡單的outbound NAT規則,10.0.0.0/24是內部局域網:

iptables -t nat -A POSTROUTING \ 
         -s 10.0.0.0/24 -j MASQUERADE 

該規則匹配所有來自內網的包,並對他們進行偽裝。如果只有一個路由連接到internat這種方法是非常有效率的,通過該路有的所有流量都是公網的流量。然而,如果有連接到其它私有網絡的路由存在,比如VPN或無力WAN連接,你可能就不會使用地址偽裝。

克服這個限制的一個簡單方法是基於物理接口建立NAT規則,而不是使用基於網絡地址的方式。

iptables -t nat -A POSTROUTING \ 
         -o eth0 -j MASQUERADE 

該規則假設eth0是外部接口,該規則會匹配所有離開這個接口的包。與前面的規則不同的是,其他內網的數據包通過其它接口訪問公網時不會匹配這條規則(比如OpenVPN的連接)。

雖然許多連接是通過不同的接口路由,但並不能假設所有的鏈接都是這樣。一個例子是基於KAME的IPsec VPN連接(比如Openswan)就不是使用虛擬接口。

不適用上面的接口匹配技術的另一種情況是如果向外的接口(連接到Internet的接口)連接路由到其他私有網絡的中間網絡,而不是連接到Internet。

通過匹配物理接口來設計的防火牆規則可以使用在一些人為限制方面,並且依賴網絡拓撲。

後來發現,ipset還有另一個應用。假設有一個本地LAN (10.0.0.0/24)需要連接到internet,除此之外還有三個本地網絡(10.30.30.0/24, 10.40.40.0/24, 192.168.4.0/23和172.22.0.0/22 ),執行下面的命令:


ipset -N routed_nets nethash 
ipset -A routed_nets 10.30.30.0/24 
ipset -A routed_nets 10.40.40.0/24 
ipset -A routed_nets 192.168.4.0/23 
ipset -A routed_nets 172.22.0.0/22 
iptables - t nat -A POSTROUTING \ 
         -s 10.0.0.0/24 \ 
         -m set ! --set routed_nets dst \ 
         -j MASQUERADE

如我們所見,ipset簡單的實現了精確匹配。該規則偽裝所有來自(10.0.0.0/24)的數據包,而不處理其他在routed_nets集合中的網絡的包。由於該配置完全基於網絡地址,所以你完全不用擔心其他特殊的網絡連接(比如VPN),也不用擔心物理接口和網絡拓撲。

Limiting Certain PCs to Have Access Only to Certain Public Hosts

假設老闆較關心員工上班時間上網問題,請你限制員工的PC只能訪問指定的幾個網站,但是不想所有的內部PC都受到限制。

限制3台PC (10.0.0.5, 10.0.0.6 and 10.0.0.7)只能訪問worksite1.com,worksite2.com和worksite3.com。執行下面的命令:
ipset -N limited_hosts iphash 
ipset -A limited_hosts 10.0.0.5 
ipset -A limited_hosts 10.0.0.6 
ipset -A limited_hosts 10.0.0.7 
ipset -N allowed_sites iphash 
ipset -A allowed_sites worksite1.com 
ipset -A allowed_sites worksite2.com 
ipset -A allowed_sites worksite3.com 
iptables -I FORWARD \
         -m set --set limited_hosts src \ 
         -m set ! --set allowed_sites dst \ 
         -j DROP 

該例子在一條規則裡使用了兩個集合。如果源地址匹配limited_hosts目的地址不匹配allowed_sites,數據包就被丟棄。

注意該規則被添加到了FORWARD鏈,它不會影響防火牆主機自己的通信。

 Blocking Access to Hosts for All but Certain PCs (Inverse Scenario)

假設老闆想阻止員工訪問幾個特定的網站,但是不阻止他自己的PC和他助理的PC。在這個例子裡,我們可以匹配老闆和助理的PC的MAC地址,而不是匹配IP地址。假設他們的MAC是11:11:11:11:11:11和22:22:22:22:22:22,需要組織員工訪問的站點是badsite1.com, badsite2.com和badsite3.com. 

這次我們不使用第二個集合匹配MAC地址,而是使用多個iptables命令,利用MARK target標記數據包,而利用後面的規則處理被標記的數據包。

ipset -N blocked_sites iphash 
ipset -A blocked_sites badsite1.com 
ipset -A blocked_sites badsite2.com 
ipset -A blocked_sites badsite3.com
iptables -I FORWARD -m mark --mark 0x187 -j DROP 
iptables -I FORWARD \ 
         -m mark --mark 0x187 \ 
         -m mac --mac-source 11:11:11:11:11:11 \ 
         -j MARK --set-mark 0x0 
iptables -I FORWARD \ 
         -m mark --mark 0x187 \ 
         -m mac --mac-source 22:22:22:22:22:22 \ 
         -j MARK --set-mark 0x0 
iptables - I FORWARD \ 
         -m set --set blocked_sites dst \ 
         -j MARK --set-mark 0x187 

上面的例子,由於沒有使用ipset完成所有的匹配工作,所以使用的命令比較多,而且比較複雜。由於用到了多個iptables命令,所以各個命令的順序是非常重要的。

注意這些規則是使用—I (insert)選項而不是使用-A (append)選項。當一個規則被插入,他會被添加的鏈的頂端,而以前的規則自動下移。因為每一格規則都是被插入德,所以實際的有效順序是相反的。

最後一個iptables命令實際在FORWARD鏈的頂端。該規則匹配所有目的地址與blocked_sites集合相匹配的數據包,然後將這些數據標記為0x187.下面的兩個規則匹配來自特定MAC地址並且已經標記為0x187的數據包,然後將他們標記為0。

最後,最後的iptables規則丟棄所有的被標記為0x187的數據包。除了來源是兩個特定MAC地址的數據包,他將會匹配所有的目標地址在blocked_sites集合裡的數據包。

這是解決問題的一種方法。還有一些其他方法,除了使用第二個ipset集合的方法,還可以使用用戶自定義鍊等。

使用第二個ipset集合代替標記的方法是不可能完成上面的要求的,因為ipset沒有machash集合類型,只有集合類型,但是他要求同時匹配IP和MAC,而不是只匹配MAC地址。

警告:在大多數實際環境裡,這個方法可能不可行,應為大部分你需要屏蔽的網站他們的主機都有多個ip地址(比如Facebook, MySpace等等),而且這些ip會頻繁的更換。iptables/ipset的一個限制是主機名只有被解析為單個ip地址時才能使用。

而且,主機名lookup只有在命令執行時發生,所以如果ip地址改變了,防火牆是不會意識到的,而是仍然使用以前的ip地址。基於這個原因,一個完成Web訪問限制的更好的方法是使用HTTP代理,比如Squid。

Automatically Ban Hosts That Attempt to Access Invalid Services

ipset為iptables提供了目標擴展功能,它提供了一種向集合動態添加和刪除目標的機制。不必手動使用ipset命令添加目標,而是在運行時通過iptables自動添加。

比如,如果遠程主機嘗試連接端口25,但是你並沒有運行SMTP服務,我們懷疑對方不懷好意,所以我們在對方還沒有乾什麼壞事前就組織他的其他嘗試,使用下面的規則:

ipset -N banned_hosts iphash 
iptables -A INPUT \ 
         -p tcp --dport 25 \ 
         -j SET --add-set banned_hosts src 
iptables -A INPUT \ 
         -m set --set banned_hosts src \ 
         -j DROP 

如果從端口25接收到數據包,假設來源地址是1.1.1.1,那麼該地址馬上就被添加到banned_hosts集合,和下面的例子等效:

ipset -A banned_hosts 1.1.1.1 

所有的1.1.1.1的連接都會被阻塞。

他同樣會阻止其他主機對本設備進行端口掃描,除非他不掃描25號端口。
Clearing the Running Config 

如果你想清除ipset和iptables的配置,將防火牆reset,運行下面的命令:

iptables -P INPUT ACCEPT 
iptables -P OUTPUT ACCEPT 
iptables -P FORWARD ACCEPT 
iptables -t filter -F
iptables -t raw -F 
iptables -t nat -F 
iptables -t mangle -F 
ipset -F 
ipset -X 

如果集合正在被使用,意味著其它的iptables規則正在引用該集合,就不能對集合進行銷毀(ipset - X),所以為了在任何狀態下都完成reset,iptables鏈必須首先清除。

Conclusion

ipset為netfilter/iptables在增加了很多有用的特性和功能,正如本篇文章描述的,ipset不僅提供了新的防火牆配製的可能性,而且他減少了之前只使用iptables來配置防火牆的困難。

任何時候,如果你想將防火牆規則應用到一個組,你應該使用ipset。正如前面的例子,你可以通過將ipset與iptables的其它特性相結合,來完成各種各樣的網絡配置和策略。

下一次你再進行防火牆配置時,考慮使用ipset。我相信你會被他的可用性和靈活性震驚。
Resources 

Netfilter/iptables Project Home Page: http://www.netfilter.org 

ipset Home Page: http://ipset.netfilter.org 

原文地址:http://www.linuxjournal.com/content/advanced-firewall-configurations -ipset?page=0,0 

2018年9月18日 星期二

openwrt中使用ubus實現進程通信的原理

From:http://blog.csdn.net/jasonchen_gbd/article/details/45627967
ubus為openwrt平台開發中的進程間通信提供了一個通用的框架。它讓進程間通信的實現變得非常簡單,並且ubus具有很強的可移植性,可以很方便的移植到其他linux平台上使用。本文描述了ubus的實現原理和整體框架。
ubus源碼可通過Git庫git://nbd.name/luci2/ubus.git獲得,其依賴的ubox庫的git庫:git://nbd.name/luci2/ubox.git。

1. ubus的實現框架

ubus實現的基礎是unix socket,即本地socket,它相對於用於網絡通信的inet socket更高效,更具可靠性。unix socket客戶端和服務器的實現方式和網絡socket類似,讀者如果還不太熟悉可查閱相關資料。

我們知道實現一個簡單的unix socket服務器和客戶端需要做如下工作:
  1. 建立一個socket server端,綁定到一個本地socket文件,並監聽clients的連接。
  2. 建立一個或多個socket client端,連接server。
  3. client和server相互發送消息。
  4. client或server收到對方消息後,針對具體消息進行相應處理。
ubus同樣實現了上述組件,並對socket連接以及消息傳輸和處理進行了封裝:
  • 1.  ubus提供了一個socket server:ubusd因此開發者不需要自己實現server端。
  • 2.  ubus提供了創建socket client端的接口,並且提供了三種現成的客戶端供用戶直接使用:
1) 為shell腳本提供的client端。
2) 為lua腳本提供的client接口。
3) 為C語言提供的client接口。
可見ubus對shell和lua增加了支持,後面會介紹這些客戶端的用法。
  • 3.  ubus對client和server之間通信的消息格式進行了定義:client和server都必須將消息封裝成json消息格式
  • 4.  ubus對client端的消息處理抽像出“對象(object)”和“方法(method)”的概念。一個對像中包含多個方法,client需要向server註冊收到特定json消息時的處理方法。對象和方法都有自己的名字,發送請求方只需在消息中指定要調用的對象和方法的名字即可。
使用ubus時需要引用一些動態庫,主要包括:
  •  libubus.so:ubus向外部提供的編程接口,例如創建socket,進行監聽和連接,發送消息等接口函數。
  •  libubox.so:ubus向外部提供的編程接口,例如等待和讀取消息。
  •  libblobmsg.so,libjson.so:提供了封裝和解析json數據的接口,編程時不需要直接使用libjson.so,而是使用libblobmsg.so提供的更靈活的接口函數。
ubus中各組件的關係如下圖所示:

使用ubus進行進程間通信不需要編寫大量代碼,只需按照固定模式調用ubus提供的API即可。在ubus源碼中examples目錄下有一些例子可以參考。

2. ubus的實現原理

下面以一個例子說明ubus的工作原理:
下圖中,client2試圖通過ubus修改ip地址,而修改ip地址的函數在client1中定義。
client2進行請求的整個過程為:
1. client1向ubusd註冊了兩個對象:“interface”和“dotalk”,其中“interface”對像中註冊了兩個method:“getlanip”和“setlanip”,對應的處理函數分別為func1()和func2 ()。“dotalk”對像中註冊了兩個method:“sayhi”和“saybye”,對應的處理函數分別為func3()和func4()。
2. 接著創建一個client2用來與client1通信,注意,兩個client之間不能直接通信,需要經ubusd(server)中轉。
3. client2就是在前面講到的shell/lua/C客戶端。假設這裡使用shell客戶端,在終端輸入以下命令:
ubus call interface setlanip '{“ip”:“10.0.0.1”, “mask”:24}'
ubus的call命令帶三個參數:請求的對象名,需要調用的方法名,要傳給方法的參數。
4. 消息發到server後,server根據對象名找到應該將請求轉發給client1,然後將消息發送到client1,client1進而調用func2()接受參數並處理,如果處理完成後需要回复client2,則發送回复消息。

接下來介紹一下上述過程中,ubus內部的處理機制,雖然使用ubus進行進程間通信不需要關注這些實現細節,但有助於加深對ubus實現原理的理解。
下圖中,client1註冊對象和方法,其實可認為是服務提供端,只不過對於ubusd來講是一個socket client。client2去調用client1註冊的方法。

3. ubus的應用場景和局限性

ubus可用於兩個進程之間的通信,並以類似json格式進行數據交互。ubus的常見場景為:
  • “客戶端--服務器”形式的交互,即進程A註冊一系列的服務,進程B去調用這些服務。
  • ubus支持以“訂閱-- 通知”的方式進行進程通信,即進程A提供訂閱服務,其他進程可以選擇訂閱或退訂該服務,進程A可以向所有訂閱者發送消息。
由於ubus實現方式的限制,在一些場景中不適宜使用ubus:
  1. ubus用於少量數據的傳輸,如果數據量很大或是數據交互很頻繁,則不宜用ubus。經過測試,當ubus一次傳輸數據量超過60KB,就不能正常工作了。
  2. ubus對多線程支持的不好,例如在多個線程中去請求同一個服務,就有可能出現不可預知的結果。
  3. 不建議遞歸調用ubus,例如進程A去調用進程B的服務,而B的該服務需要調用進程C的服務,之後C將結果返回給B,然後B將結果返回給A。如果不得不這樣做,需要在調用過程中避免全局變量的重用問題。

4. ubus源碼簡析

下面介紹一下ubusd和ubus client工作時的代碼流程,這里為了便於理解,只介紹大致的流程,欲了解詳細的實現請讀者自行閱讀源碼。

4.1 ubusd工作流程

ubusd 的初始化所做的工作如下:
1. epoll_create(32)創建出一個poll_fd。
2.創建一個UDP unix socket,並添加到poll_fd的監聽隊列。
3.進行epoll_wait()等待消息。收到消息後的處理函數定義如下:
[cpp]  view plaincopy 
  1. static struct  uloop_fd server_fd = {   
  2. .cb = server_cb,  
  3. };  
即調用server_cb()函數。
4. server_cb()函數中的工作為:
(1)進行accept(),接受client連接,並為該連接生成一個client_fd。
(2)為client分配一個client id,用於ubusd區分不同的client。
(3)向client發送一個HELLO消息作為連接建立的標誌。
(4)將client_fd添加到poll_fd的監聽隊列中,用於監聽client發過來的消息,消息處理函數為client_cb()。
也就是說ubusd監聽兩種消息,一種是新client的連接請求,一種是現有的每個client發過來的數據。
當ubusd收到一個client的數據後,調用client_cb()函數的處理過程:
1.先檢查一下是否有需要向這個client回复的數據(可能是上一次請求沒處理完),如果有,先發送這些遺留數據。
2.讀取socket上的數據,根據消息類型(數據中都指定了消息類型的)調用相應的處理函數,消息類型和處理函數定義如下:
[cpp]  view plaincopy 
  1. static const  ubus_cmd_cb handlers[__UBUS_MSG_LAST] = {   
  2. [UBUS_MSG_PING] = ubusd_send_pong,  
  3. [UBUS_MSG_ADD_OBJECT] = ubusd_handle_add_object,  
  4. [UBUS_MSG_REMOVE_OBJECT] = ubusd_handle_remove_object,  
  5. [UBUS_MSG_LOOKUP] = ubusd_handle_lookup,  
  6. [UBUS_MSG_INVOKE] = ubusd_handle_invoke,  
  7. [UBUS_MSG_STATUS] = ubusd_handle_response,  
  8. [UBUS_MSG_DATA] = ubusd_handle_response,  
  9. [UBUS_MSG_SUBSCRIBE] = ubusd_handle_add_watch,  
  10. [UBUS_MSG_UNSUBSCRIBE] = ubusd_handle_remove_watch,  
  11. [UBUS_MSG_NOTIFY] = ubusd_handle_notify,  
  12. };  
例如,如果收到invoke消息,就調用ubusd_handle_invoke()函數處理。
這些處理函數可能是ubusd處理完後需要回發給client數據,或者是將消息轉發給另一個client(如果發送請求的client需要和另一個client進行通信)。
3.處理完成後,向client發送處理結果,例如UBUS_STATUS_OK。(注意,client發送數據是UBUS_MSG_DATA類型的)

4.2 client的工作流程

ubus call obj method的工作流程:
1.創建一個unix socket(UDP)連接ubusd,並接收到server發過來的HELLO消息。
2. ubus call命令由ubus_cli_call()函數進行處理,先向ubusd發送lookup消息請求obj的id。然後向ubusd發送invoke消息來調用obj的method方法。
3.創建epoll_fd並將client的fd添加到監聽列表中等待消息。
4. client收到消息後的處理函數為ubus_handle_data(),其中UBUS_MSG_DATA類型的數據receive_call_result_data()函數協助解析。
被call的client的工作流程:
和ubus客戶端的流程相似,只是變成了接受請求並調用處理函數

How to repair and clone disk with ddrescue

  ddrescue  is a tool that can be used to repair and clone disks on a  Linux system . This includes hard drives, partitions, DVD discs, flas...