1.Iptables是什么
iptables是linux系统下用来做防火墙的二进制文件(linux上位于/sbin/iptables,android中位于/system/bin/iptables),底层依赖于内核的netfilter模块,用来完成封包过滤、封包重定向和网络地址转换(NAT)等功能(在android上需要root使用)。
2.Iptables怎么用
举个例子来简单看看iptables命令的基本用法。
iptables -t nat -A OUTPUT -p tcp -j REDIRECT --to 8123
意思是在nat转发表的OUTPUT输出链中增加这样一条规则:倘若OUTPUT输出链拦到了tcp请求,则将其重定向到本地的8123端口。
可以看到iptables中有表、链和规则的概念,那么先通过iptables传输数据包的过程来简单了解下表和链是什么以及他们之间的关系。
当一个数据包进入网卡时,它首先进入PREROUTING链,内核根据数据包目的IP判断是否需要转送出去。
如果数据包就是进入本机的,它就会沿着图向下移动,到达INPUT链。数据包到了INPUT链后,任何进程都会收到它。本机上运行的程序可以发送数据包,这些数据包会经过OUTPUT链,然后到达POSTROUTING链输出。
如果数据包是要转发出去的,且内核允许转发,数据包就会如图所示向右移动,经过FORWARD链,然后到达POSTROUTING链输出。
可以看到链就是对数据包传输路径的一种抽象,一个数据包根据其具体场景以固定的顺序依次经过PREROUTING、INPUT等各个链,在经过各个链时,又有不同的表在监听这个链,而nat、filter等表中有包含一系列的规则,当一个数据包到达一个链时,iptables就会从链中第一条规则开始检查,看该数据包是否满足规则所定义的条件。如果满足,系统就会根据该条规则所定义的方法处理该数据包;否则iptables将继续检查下一条规则。
值得注意的是,
不同的表允许监听的链是不同的,如一般用来做网络地址转换的nat表只能监听PREOUTROUTING、POSTROUTING和OUTPUT链。
监听同一个链上的多个表的检查的顺序是有先后的,raw->mangle->nat->filter。
至此我们了解了表、链和规则是什么以及他们之间的关系,下面来具体看下iptables命令的基本用法。
更多关于各command、parameter的具体含义以及用法可以参考https://wangchujiang.com/linux-command/c/iptables.html
3.Iptables的基本工作原理
iptables对网络数据包做过滤或拦截时其维度只能局限于网络数据包收发的ip地址、端口号、网卡、tcp/udp协议,因此可以推测iptables最终是在ip层对网络数据包做的拦截。
那iptables基于netfilter具体是怎么做到在各个链上对数据包做拦截的呢?
/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);
...
可以看到内核在每一个数据转发的关键节点都调用了NF_HOOK这个宏,来看下NF_HOOK这个宏干了啥
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn)
({int __ret;
if (list_empty(&nf_hooks[pf][hook]) ||//查看这个hook点是否有hook函数要执行
(__ret=nf_hook_slow(pf, hook, &(skb), indev, outdev, okfn, INT_MIN)) == 1)//执行具体的hook函数
__ret = (okfn)(skb);//若hook决定不拦截,则继续回调原有函数
__ret;})
关于NF_HOOK相关具体逻辑可参见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