Netfilter/iptables 项目由 Rusty Russe 创建于1998年,并于 1999 年建立了 Netfilter Core team,并在此后负责维护此项目,同时也于2000年3月合并进了 linux 2.3.x 版本的 linux 内核。
Netfilter/iptables 有三部分组成,分别是Netfilter 框架/Iptables(内核空间)/Iptables 命令行工具(用户空间)。
Netfilter 是一个由Linux 内核提供的框架,可以进行多种网络相关的自定义操作。
例如:
Netfilter 在 Linux 内核中表现为一系列的hook, 并允许Linux 内核模块注册为回调函数,Linux内核模块通过回调函数操作网络报文。
Netfilter 一共提供了5个hook,分别位于linux 网络栈中的各个处理节点,如下图:
--->[NF_IP_PRE_ROUTING]--->[ROUTE]--->[NF_IP_FORWARD]--->[NF_IP_POST_ROUTING]--->
| ^
| |
| [ROUTE]
v |
[NF_IP_LOCAL_IN] [NF_IP_LOCAL_OUT]
| ^
| |
v |
Netfilter Hook的意义:
NF_IP_PRE_ROUTING
: 位于路由之前,报文一致性检查之后(报文一致性检查包括: 报文版本、报文长度和checksum)。NF_IP_LOCAL_IN
: 位于报文经过路由之后,并且目的是本机的。NF_IP_FORWARD
:位于在报文路由之后,目的地非本机的。NF_IP_LOCAL_OUT
: 由本机发出去的报文,并且在路由之前。NF_IP_POST_ROUTING
: 所有即将离开本机的报文。Linux 内核模块可以注册到任何的hook,注册的回调函数也必需指定优先级。当一个报文通过hook的时候,hook将会依据优先级调用回调函数。注册的回调函数,可以有五种返回,每种返回代表对报文不同的操作:
NF_ACCEPT
: 继续正常处理此报文,即允许报文通过。NF_DROP
: 丢弃此报文,不再进行继续处理,即拒绝此报文。NF_STOLEN
: 取走这个报文,不再继续处理。NF_QUEUE
: 报文进行重新排队,可以将报文发到用户空间的程序,进行修改或者决定是拒绝或者允许。NF_REPEAT
: 报文重新调用hook。Iptables 是基于Netfilter框架实现的报文选择系统,其可以用于报文的过滤、网络地址转换和报文修改等功能。Iptables 本质上是包含了5个规则表,而规则表则包含了一些列的报文的匹配规则以及操作目标。以下对每个规则表进行了简单说明:
Filter Table
: 是一个默认的规则表,用于报文的过滤。他注册了三个链: INPUT
、FORWARD
和OUTPUT
。NAT Table
: 主要用于NAT转换,注册了四个链:PREROUTING
、INPUT
、OUTPUT
和POSTROUTING
。Mangle Table
: 主要用于报文的修改,一共注册了五个链: PREROUTING
、OUTPUT
、INPUT
、FORWARD
和POSTROUTING
Raw Table
: 可以对报文不进行链路跟踪,其优先级在hook中注册很高,注册了两个链: PREROUTING
和OUTPUT
Security Table
: 用于强制网络接入控制,注册了三个链:INPUT
、OUTPUT
和 FORWARD
操作目标指的是否允许报文通过,如果允许即为ACCEPT
,拒绝则为DROP
。
iptables命令行工具是工作在用户空间的操作工具,用于修改内核空间的规则表,下面给出了几个例子:
拒绝来自192.168.12.4
的报文
# Drop all incoming packets from address 192.168.12.4
iptables -I INPUT -s 192.168.12.4 -j DROP
拒绝ping
任何主机
iptables -A OUTPUT -p icmp -j DROP
以下为来自man iptables
的使用方法
# Append rule-specification in selected chain
iptables [-t table] -[A] chain rule-specification [options]
# Insert one or more rules in the selected chain as the given rule number.
iptables [-t table] -I chain [rulenum] rule-specification [options]
# Replace a rule in the selected chain
iptables [-t table] -R chain rulenum rule-specification [options]
# Delete one or more rules from the selected chain.
iptables [-t table] -D chain rulenum [options]
# List all rules in the selected chain.
iptables [-t table] -[L] [chain] [options]
# Flush the selected chain.
iptables [-t table] -[F] [chain] [options]
# Set the policy for the chain to the given target.
iptables [-t table] -P chain target [options]
以下代码实现了一个简单的linux 内核模块,并且通过netfilter hook注册了一个回调函数,以此来实现禁用ICMP报文(无法从本机ping任何主机)。
/*
* This code was compiled and tested on Ubuntu 18.04.2
* with kernel version 4.15.0
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Rui");
MODULE_DESCRIPTION("A simple example netfilter module.");
MODULE_VERSION("0.0.1");
static struct nf_hook_ops *nfho = NULL;
static unsigned int hfunc(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
{
struct iphdr *iph;
if (!skb)
return NF_ACCEPT;
iph = ip_hdr(skb);
if (iph->protocol == IPPROTO_ICMP) {
return NF_DROP;
}
return NF_ACCEPT;
}
static int __init LKM_init(void)
{
nfho = (struct nf_hook_ops*)kcalloc(1, sizeof(struct nf_hook_ops), GFP_KERNEL);
/* Initialize netfilter hook */
nfho->hook = (nf_hookfn*)hfunc; /* hook function */
nfho->hooknum = NF_INET_PRE_ROUTING; /* received packets */
nfho->pf = PF_INET; /* IPv4 */
nfho->priority = NF_IP_PRI_FIRST; /* max hook priority */
nf_register_net_hook(&init_net, nfho);
}
static void __exit LKM_exit(void)
{
nf_unregister_net_hook(&init_net, nfho);
kfree(nfho);
}
module_init(LKM_init);
module_exit(LKM_exit);
Makefile
obj-m += netfilter-LKM.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
在Bash Shell环境下编译,并且加载linux内核模块。
make
insmod netfilter-LKM.ko
通过 rmmod netfilter-LKM
移除linux内核模块。
1 Netfilter
2 Linux Kernel Communication Netfilter Hooks
3 Netfilter Architecture