1.Iptables是什么
iptables是linux系統(tǒng)下用來做防火墻的二進(jìn)制文件(linux上位于/sbin/iptables娩脾,android中位于/system/bin/iptables)赵誓,底層依賴于內(nèi)核的netfilter模塊,用來完成封包過濾柿赊、封包重定向和網(wǎng)絡(luò)地址轉(zhuǎn)換(NAT)等功能(在android上需要root使用)架曹。
2.Iptables怎么用
舉個(gè)例子來簡單看看iptables命令的基本用法。
iptables -t nat -A OUTPUT -p tcp -j REDIRECT --to 8123
意思是在nat轉(zhuǎn)發(fā)表的OUTPUT輸出鏈中增加這樣一條規(guī)則:倘若OUTPUT輸出鏈攔到了tcp請求闹瞧,則將其重定向到本地的8123端口绑雄。
可以看到iptables中有表、鏈和規(guī)則的概念奥邮,那么先通過iptables傳輸數(shù)據(jù)包的過程來簡單了解下表和鏈?zhǔn)鞘裁匆约八麄冎g的關(guān)系万牺。
當(dāng)一個(gè)數(shù)據(jù)包進(jìn)入網(wǎng)卡時(shí)罗珍,它首先進(jìn)入PREROUTING鏈,內(nèi)核根據(jù)數(shù)據(jù)包目的IP判斷是否需要轉(zhuǎn)送出去脚粟。
如果數(shù)據(jù)包就是進(jìn)入本機(jī)的覆旱,它就會(huì)沿著圖向下移動(dòng),到達(dá)INPUT鏈核无。數(shù)據(jù)包到了INPUT鏈后扣唱,任何進(jìn)程都會(huì)收到它。本機(jī)上運(yùn)行的程序可以發(fā)送數(shù)據(jù)包团南,這些數(shù)據(jù)包會(huì)經(jīng)過OUTPUT鏈噪沙,然后到達(dá)POSTROUTING鏈輸出。
如果數(shù)據(jù)包是要轉(zhuǎn)發(fā)出去的吐根,且內(nèi)核允許轉(zhuǎn)發(fā)正歼,數(shù)據(jù)包就會(huì)如圖所示向右移動(dòng),經(jīng)過FORWARD鏈拷橘,然后到達(dá)POSTROUTING鏈輸出局义。
可以看到鏈就是對(duì)數(shù)據(jù)包傳輸路徑的一種抽象,一個(gè)數(shù)據(jù)包根據(jù)其具體場景以固定的順序依次經(jīng)過PREROUTING冗疮、INPUT等各個(gè)鏈萄唇,在經(jīng)過各個(gè)鏈時(shí),又有不同的表在監(jiān)聽這個(gè)鏈术幔,而nat另萤、filter等表中有包含一系列的規(guī)則,當(dāng)一個(gè)數(shù)據(jù)包到達(dá)一個(gè)鏈時(shí)特愿,iptables就會(huì)從鏈中第一條規(guī)則開始檢查仲墨,看該數(shù)據(jù)包是否滿足規(guī)則所定義的條件。如果滿足揍障,系統(tǒng)就會(huì)根據(jù)該條規(guī)則所定義的方法處理該數(shù)據(jù)包目养;否則iptables將繼續(xù)檢查下一條規(guī)則。
值得注意的是毒嫡,
不同的表允許監(jiān)聽的鏈?zhǔn)遣煌陌┮希缫话阌脕碜鼍W(wǎng)絡(luò)地址轉(zhuǎn)換的nat表只能監(jiān)聽PREOUTROUTING、POSTROUTING和OUTPUT鏈兜畸。
監(jiān)聽同一個(gè)鏈上的多個(gè)表的檢查的順序是有先后的努释,raw->mangle->nat->filter。
至此我們了解了表咬摇、鏈和規(guī)則是什么以及他們之間的關(guān)系伐蒂,下面來具體看下iptables命令的基本用法。
更多關(guān)于各command肛鹏、parameter的具體含義以及用法可以參考https://wangchujiang.com/linux-command/c/iptables.html
3.Iptables的基本工作原理
iptables對(duì)網(wǎng)絡(luò)數(shù)據(jù)包做過濾或攔截時(shí)其維度只能局限于網(wǎng)絡(luò)數(shù)據(jù)包收發(fā)的ip地址逸邦、端口號(hào)恩沛、網(wǎng)卡、tcp/udp協(xié)議缕减,因此可以推測iptables最終是在ip層對(duì)網(wǎng)絡(luò)數(shù)據(jù)包做的攔截雷客。
那iptables基于netfilter具體是怎么做到在各個(gè)鏈上對(duì)數(shù)據(jù)包做攔截的呢?
/net/ipv4/ip_output.c
int ip_output(struct sock *sk, struct sk_buff *skb)
{
...
return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb, NULL, dev,
ip_finish_output,
!(IPCB(skb)->flags & IPSKB_REROUTED));
}
/net/ipv4/ip_input.c
int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
{
...
return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, skb, dev, NULL,
ip_rcv_finish);
...
/net/ipv4/ip_forward.c
int ip_forward(struct sk_buff *skb)
{
...
return NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD, skb, skb->dev,
rt->dst.dev, ip_forward_finish);
...
可以看到內(nèi)核在每一個(gè)數(shù)據(jù)轉(zhuǎn)發(fā)的關(guān)鍵節(jié)點(diǎn)都調(diào)用了NF_HOOK這個(gè)宏桥狡,來看下NF_HOOK這個(gè)宏干了啥
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn)
({int __ret;
if (list_empty(&nf_hooks[pf][hook]) ||//查看這個(gè)hook點(diǎn)是否有hook函數(shù)要執(zhí)行
(__ret=nf_hook_slow(pf, hook, &(skb), indev, outdev, okfn, INT_MIN)) == 1)//執(zhí)行具體的hook函數(shù)
__ret = (okfn)(skb);//若hook決定不攔截搅裙,則繼續(xù)回調(diào)原有函數(shù)
__ret;})
關(guān)于NF_HOOK相關(guān)具體邏輯可參見https://sites.google.com/site/ibmsdu/network-security-development/netfilter%E8%AE%BE%E8%AE%A1%E4%B8%8E%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90