【LINUX协议栈】netfilter之filter表、mangle表、nat表、raw表

1、filter表

  • Filter表 是以kernel module形式加载的(insmod iptable_filter)
  • 入口在net/ipv4/netfilter/iptable_filter.c中
  • Filter表主要在以下Hook点起作用:
#define FILTER_VALID_HOOKS ((1 << NF_INET_LOCAL_IN) | \
			    (1 << NF_INET_FORWARD) | \
			    (1 << NF_INET_LOCAL_OUT))
即只在数据包的接收、转发、发送时起作用

1.1 filter表信息 packet_filter

static const struct xt_table packet_filter = {
	.name		= "filter",
	.valid_hooks	= FILTER_VALID_HOOKS,
	.me		= THIS_MODULE,
	.af		= NFPROTO_IPV4,
	.priority	= NF_IP_PRI_FILTER,
};

1.2 内核加载初始化 iptable_filter_init

static struct pernet_operations iptable_filter_net_ops = {
	.init = iptable_filter_net_init,
	.exit = iptable_filter_net_exit,
};

static int __init iptable_filter_init(void)
{
	int ret;

	ret = register_pernet_subsys(&iptable_filter_net_ops);
	if (ret < 0)
		return ret;

	/* Register hooks */
	filter_ops = xt_hook_link(&packet_filter, iptable_filter_hook);
	if (IS_ERR(filter_ops)) {
		ret = PTR_ERR(filter_ops);
		unregister_pernet_subsys(&iptable_filter_net_ops);
	}

	return ret;
}

1.3 filter表初始化 iptable_filter_net_init

static int __net_init iptable_filter_net_init(struct net *net)
{
	struct ipt_replace *repl;
	/* 分配初始化表,用于下面的表注册 */
	repl = ipt_alloc_initial_table(&packet_filter);
	if (repl == NULL)
		return -ENOMEM;
	/* Entry 1 is the FORWARD hook */
	/* 入口1是否为FORWARD钩子点时的verdict值设置 */
	((struct ipt_standard *)repl->entries)[1].target.verdict =
		forward ? -NF_ACCEPT - 1 : -NF_DROP - 1;
	/* 注册filter表,注册后,ipv4.iptable_filter保存了注册后的新表 */
	net->ipv4.iptable_filter =
		ipt_register_table(net, &packet_filter, repl);
	/* 释放初始化表 */
	kfree(repl);
	return PTR_ERR_OR_ZERO(net->ipv4.iptable_filter);
}

1.4 filter表的hook定义 iptable_filter_hook

static unsigned int
iptable_filter_hook(void *priv, struct sk_buff *skb,
		    const struct nf_hook_state *state)
{
	if (state->hook == NF_INET_LOCAL_OUT &&
	    (skb->len < sizeof(struct iphdr) ||
	     ip_hdrlen(skb) < sizeof(struct iphdr)))
		/* root is playing with raw sockets. */
		return NF_ACCEPT;

	return ipt_do_table(skb, state, state->net->ipv4.iptable_filter);
}

2、mangle表

  • 入口在net\ipv4\netfilter\iptable_mangle.c中
  • mangle表主要在以下Hook点起作用:
#define MANGLE_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | \
			    (1 << NF_INET_LOCAL_IN) | \
			    (1 << NF_INET_FORWARD) | \
			    (1 << NF_INET_LOCAL_OUT) | \
			    (1 << NF_INET_POST_ROUTING))
主要功能是根据规则修改数据包的一些标志位,以便其他规则或程序可以利用这种标志对数据包进行过滤或策略路由

2.1 mangle表信息 packet_mangler

static const struct xt_table packet_mangler = {
	.name		= "mangle",
	.valid_hooks	= MANGLE_VALID_HOOKS,
	.me		= THIS_MODULE,
	.af		= NFPROTO_IPV4,
	.priority	= NF_IP_PRI_MANGLE,
};

2.2 内核加载初始化 iptable_mangle_init

static struct pernet_operations iptable_mangle_net_ops = {
	.init = iptable_mangle_net_init,
	.exit = iptable_mangle_net_exit,
};

static int __init iptable_mangle_init(void)
{
	int ret;

	ret = register_pernet_subsys(&iptable_mangle_net_ops);
	if (ret < 0)
		return ret;

	/* Register hooks */
	mangle_ops = xt_hook_link(&packet_mangler, iptable_mangle_hook);
	if (IS_ERR(mangle_ops)) {
		ret = PTR_ERR(mangle_ops);
		unregister_pernet_subsys(&iptable_mangle_net_ops);
	}

	return ret;
}

2.3mangle表初始化 iptable_mangle_net_init

static int __net_init iptable_mangle_net_init(struct net *net)
{
	struct ipt_replace *repl;

	repl = ipt_alloc_initial_table(&packet_mangler);
	if (repl == NULL)
		return -ENOMEM;
	net->ipv4.iptable_mangle =
		ipt_register_table(net, &packet_mangler, repl);
	kfree(repl);
	return PTR_ERR_OR_ZERO(net->ipv4.iptable_mangle);
}

2.4 mangle表的hook定义 iptable_mangle_hook

/* The work comes in here from netfilter.c. */
static unsigned int
iptable_mangle_hook(void *priv,
		     struct sk_buff *skb,
		     const struct nf_hook_state *state)
{
	if (state->hook == NF_INET_LOCAL_OUT)
		return ipt_mangle_out(skb, state);
	if (state->hook == NF_INET_POST_ROUTING)
		return ipt_do_table(skb, state,
				    state->net->ipv4.iptable_mangle);
	/* PREROUTING/INPUT/FORWARD: */
	return ipt_do_table(skb, state, state->net->ipv4.iptable_mangle);
}

3、nat表

  • 入口在net\ipv4\netfilter\iptable_nat.c中

3.1 nat表信息

static const struct xt_table nf_nat_ipv4_table = {
	.name		= "nat",
	.valid_hooks	= (1 << NF_INET_PRE_ROUTING) |
			  (1 << NF_INET_POST_ROUTING) |
			  (1 << NF_INET_LOCAL_OUT) |
			  (1 << NF_INET_LOCAL_IN),
	.me		= THIS_MODULE,
	.af		= NFPROTO_IPV4,
};

3.2内核加载初始化 iptable_nat_init

static int __init iptable_nat_init(void)
{
	int err;
	//注册pernet函数,其init函数会初始化nf_nat_ipv4_table
	err = register_pernet_subsys(&iptable_nat_net_ops);
	if (err < 0)
		goto err1;
	//注册nat的hook函数
	err = nf_register_hooks(nf_nat_ipv4_ops, ARRAY_SIZE(nf_nat_ipv4_ops));
	if (err < 0)
		goto err2;
	return 0;

err2:
	unregister_pernet_subsys(&iptable_nat_net_ops);
err1:
	return err;
}

3.3 nat表初始化 iptable_nat_net_init

static struct pernet_operations iptable_nat_net_ops = {
	.init	= iptable_nat_net_init,
	.exit	= iptable_nat_net_exit,
};

static int __net_init iptable_nat_net_init(struct net *net)
{
	struct ipt_replace *repl;
	/* 分配初始化表,用于下面的注册 */
	repl = ipt_alloc_initial_table(&nf_nat_ipv4_table);
	if (repl == NULL)
		return -ENOMEM;
	/* 表注册 */
	net->ipv4.nat_table = ipt_register_table(net, &nf_nat_ipv4_table, repl);
	kfree(repl);
	return PTR_ERR_OR_ZERO(net->ipv4.nat_table);
}

3.4 nat表的hook定义 nf_nat_ipv4_ops

static struct nf_hook_ops nf_nat_ipv4_ops[] __read_mostly = {
	/* Before packet filtering, change destination */
	{
		.hook		= iptable_nat_ipv4_in,
		.pf		= NFPROTO_IPV4,
		.hooknum	= NF_INET_PRE_ROUTING,
		.priority	= NF_IP_PRI_NAT_DST,
	},
	/* After packet filtering, change source */
	{
		.hook		= iptable_nat_ipv4_out,
		.pf		= NFPROTO_IPV4,
		.hooknum	= NF_INET_POST_ROUTING,
		.priority	= NF_IP_PRI_NAT_SRC,
	},
	/* Before packet filtering, change destination */
	{
		.hook		= iptable_nat_ipv4_local_fn,
		.pf		= NFPROTO_IPV4,
		.hooknum	= NF_INET_LOCAL_OUT,
		.priority	= NF_IP_PRI_NAT_DST,
	},
	/* After packet filtering, change source */
	{
		.hook		= iptable_nat_ipv4_fn,
		.pf		= NFPROTO_IPV4,
		.hooknum	= NF_INET_LOCAL_IN,
		.priority	= NF_IP_PRI_NAT_SRC,
	},
};

4、raw表

  • 入口在net\ipv4\netfilter\iptable_raw.c中
  • raw表主要在以下Hook点起作用:
#define RAW_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT))

4.1 raw表信息 packet_raw

static const struct xt_table packet_raw = {
	.name = "raw",
	.valid_hooks =  RAW_VALID_HOOKS,
	.me = THIS_MODULE,
	.af = NFPROTO_IPV4,
	.priority = NF_IP_PRI_RAW,
};

4.2内核加载初始化 iptable_raw_init

static struct pernet_operations iptable_raw_net_ops = {
	.init = iptable_raw_net_init,
	.exit = iptable_raw_net_exit,
};

static int __init iptable_raw_init(void)
{
	int ret;

	ret = register_pernet_subsys(&iptable_raw_net_ops);
	if (ret < 0)
		return ret;

	/* Register hooks */
	rawtable_ops = xt_hook_link(&packet_raw, iptable_raw_hook);
	if (IS_ERR(rawtable_ops)) {
		ret = PTR_ERR(rawtable_ops);
		unregister_pernet_subsys(&iptable_raw_net_ops);
	}

	return ret;
}

4.3 raw表初始化 iptable_raw_net_init

static int __net_init iptable_raw_net_init(struct net *net)
{
	struct ipt_replace *repl;

	repl = ipt_alloc_initial_table(&packet_raw);
	if (repl == NULL)
		return -ENOMEM;
	net->ipv4.iptable_raw =
		ipt_register_table(net, &packet_raw, repl);
	kfree(repl);
	return PTR_ERR_OR_ZERO(net->ipv4.iptable_raw);
}

4.4 raw表的hook定义 iptable_raw_hook

/* The work comes in here from netfilter.c. */
static unsigned int
iptable_raw_hook(void *priv, struct sk_buff *skb,
		 const struct nf_hook_state *state)
{
	if (state->hook == NF_INET_LOCAL_OUT &&
	    (skb->len < sizeof(struct iphdr) ||
	     ip_hdrlen(skb) < sizeof(struct iphdr)))
		/* root is playing with raw sockets. */
		return NF_ACCEPT;

	return ipt_do_table(skb, state, state->net->ipv4.iptable_raw);
}

你可能感兴趣的:(内核协议栈,linux,网络,netfilter,协议栈,iptables)