修改《netfilter filter表(二)》的hello_open函数,将ipt_entry的信息打印处理,代码如下:
char* get_verdict(int verdict)
{
	verdict = -(verdict + 1);
	char* p = "";
	switch (verdict)
	{
		case NF_DROP:
			p = "NF_DROP";
			break;
		case NF_ACCEPT:
			p = "NF_ACCEPT";
			break;
		case NF_STOLEN:
			p = "NF_STOLEN";
			break;
		case NF_QUEUE:
			p = "NF_QUEUE";
			break;
		case NF_REPEAT:
			p = "NF_REPEAT";
			break;
		case NF_STOP:
			p = "NF_STOP";
			break;
		default:
		break;
	}
	return p;
}
void print_entry_info(struct ipt_entry* ipt_entry)
{
	printk("  ipt_entry.target_offset = %d\n", ipt_entry->target_offset);
	printk("  ipt_entry.next_offset = %d\n", ipt_entry->next_offset);
	printk("  ipt_entry.comefrom = %d\n", ipt_entry->comefrom);
	printk("  ipt_entry.ip.src = %X\n", ipt_entry->ip.src);
	printk("  ipt_entry.ip.smsk = %X\n", ipt_entry->ip.smsk);
	printk("  ipt_entry.ip.dst = %X\n", ipt_entry->ip.dst);
	printk("  ipt_entry.ip.dmsk = %X\n", ipt_entry->ip.dmsk);
	printk("  ipt_entry.ip.iniface = %s\n", ipt_entry->ip.iniface);
	printk("  ipt_entry.ip.outiface = %s\n", ipt_entry->ip.outiface);
	printk("  ipt_entry.ip.proto = %d\n", ipt_entry->ip.proto);
	printk("  ipt_entry.ip.flags = %d\n", ipt_entry->ip.flags);
	printk("  ipt_entry.ip.invflags = %d\n", ipt_entry->ip.invflags);
	struct xt_standard_target *t = (void*)ipt_entry +  ipt_entry->target_offset;
	printk("    xt_standard_target.verdict = %s\n", get_verdict(t->verdict));
	struct xt_target *target = t->target.u.kernel.target;
	if (NULL != target)
	{
		printk("      xt_target.name = %s\n", target->name);
		printk("      xt_target.revision = %d\n", target->revision);
		printk("      xt_target.table = %s\n", target->table);
		printk("      xt_target.targetsize = %d\n", target->targetsize);
		printk("      xt_target.usersize = %d\n", target->usersize);
		printk("      xt_target.hooks = %d\n", target->hooks);
		printk("      xt_target.proto = %d\n", target->proto);
		printk("      xt_target.family = %d\n", target->family);
	}
	else
	{
		printk("no target\n");
	}
	// 有match
	if (offsetof(struct ipt_entry, elems) != ipt_entry->target_offset)
	{
		printk("have match\n");
	}
	else
	{
		printk("no match\n");
	}
}
static int hello_open(struct inode* inode, struct file*filep)
{
	... ...
	ipt_entry = table_base + filter_info->hook_entry[NF_INET_LOCAL_IN];
	ipt_entry_end = table_base + filter_info->underflow[NF_INET_LOCAL_IN];
	while (1)
	{
		if (ipt_entry >= ipt_entry_end)
		{
			
			break;
		}
		print_entry_info(ipt_entry);
		ipt_entry = (void *)ipt_entry + ipt_entry->next_offset;
	}
	
	return 0;
}其中iptable配置如下:
Chain INPUT (policy ACCEPT)
target prot opt source destination
DROP tcp -- 1.2.3.5 0.0.0.0/0
ACCEPT all -- !1.2.3.4 0.0.0.0/0
ipt_entry部分日志如下:
[ 538.451864] ipt_entry.target_offset = 112
[ 538.451865] ipt_entry.next_offset = 152
[ 538.451866] ipt_entry.comefrom = 2
[ 538.451866] ipt_entry.ip.src = 5030201
[ 538.451867] ipt_entry.ip.smsk = FFFFFFFF
[ 538.451868] ipt_entry.ip.dst = 0
[ 538.451868] ipt_entry.ip.dmsk = 0
[ 538.451869] ipt_entry.ip.iniface =
[ 538.451869] ipt_entry.ip.outiface =
[ 538.451870] ipt_entry.ip.proto = 6
[ 538.451871] ipt_entry.ip.flags = 0
[ 538.451871] ipt_entry.ip.invflags = 0
[ 538.451872] xt_standard_target.verdict = NF_DROP
[ 538.451873] xt_target.name =
[ 538.451873] xt_target.revision = 0
[ 538.451874] xt_target.table = (null)
[ 538.451874] xt_target.targetsize = 4
[ 538.451875] xt_target.usersize = 0
[ 538.451875] xt_target.hooks = 0
[ 538.451876] xt_target.proto = 0
[ 538.451877] xt_target.family = 2
[ 538.451877] no match
[ 538.451878] ipt_entry.target_offset = 112
[ 538.451878] ipt_entry.next_offset = 152
[ 538.451879] ipt_entry.comefrom = 2
[ 538.451879] ipt_entry.ip.src = 4030201
[ 538.451880] ipt_entry.ip.smsk = FFFFFFFF
[ 538.451880] ipt_entry.ip.dst = 0
[ 538.451881] ipt_entry.ip.dmsk = 0
[ 538.451882] ipt_entry.ip.iniface =
[ 538.451882] ipt_entry.ip.outiface =
[ 538.451883] ipt_entry.ip.proto = 0
[ 538.451883] ipt_entry.ip.flags = 0
[ 538.451884] ipt_entry.ip.invflags = 8
[ 538.451884] xt_standard_target.verdict = NF_ACCEPT
[ 538.451885] xt_target.name =
[ 538.451886] xt_target.revision = 0
[ 538.451886] xt_target.table = (null)
[ 538.451887] xt_target.targetsize = 4
[ 538.451887] xt_target.usersize = 0
[ 538.451888] xt_target.hooks = 0
[ 538.451888] xt_target.proto = 0
[ 538.451889] xt_target.family = 2
[ 538.451889] no match
根据上面信息,整理的关系图如下:

一个ipt_standard代表iptable表INPUT链中的一条配置,ipt_ip配置了源地址,目的地址等信息,其定义如下:
struct ipt_ip {
源地址与目的地址
struct in_addr src, dst;
源地址与目的地址的掩码
struct in_addr smsk, dmsk;
char iniface[IFNAMSIZ], outiface[IFNAMSIZ];
unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ];
协议 0 = ANY
IPPROTO_TCP 6
__u16 proto;
/* Flags word */
__u8 flags;
取反标记
#define IPT_INV_SRCIP 0x08 对源IP区反,对于第二条配置,就是源地址不是1.2.3.4的包
__u8 invflags;
};
ipt_ip表示的是标准匹配,如果有扩展匹配信息(结构体是:xt_match) ,保存在ipt_entry和xt_standard_target之间。本例中的两条配置,都不带扩展匹配,所以ipt_entry后面紧挨着xt_standard_target。是否包含扩展匹配信息,都可以通过ipt_entry的地址+target_offset,获取到xt_standard_target。
ipt_entry的地址+next_offset可以获取到下一个ipt_entry的地址。
ipt_standaard_target的verdict表示处理方法。对于标准的处理方法(如:DROP,ACCEPT),将其取反后再减1(即:-(__verdict) - 1),赋给ipt_standaard_target的verdict。给verdict赋值,可以参考下面的宏。
#define IPT_STANDARD_INIT(__verdict) \
{ \
.entry = IPT_ENTRY_INIT(sizeof(struct ipt_standard)), \
.target = XT_TARGET_INIT(XT_STANDARD_TARGET, \
sizeof(struct xt_standard_target)), \
.target.verdict = -(__verdict) - 1, \
}
最后做一个有趣的实验,将源地址为1.2.3.5的处理方法改成 NF_ACCEPT,代码如下:
void print_entry_info(struct ipt_entry* ipt_entry)
{
	... ...
	struct xt_standard_target *t = (void*)ipt_entry +  ipt_entry->target_offset;
	printk("    xt_standard_target.verdict = %s\n", get_verdict(t->verdict));
    // 新加的代码
	if (0x5030201 == ipt_entry->ip.src.s_addr)
	{
		t->verdict = -(NF_ACCEPT) - 1;
	}
	struct xt_target *target = t->target.u.kernel.target;
	if (NULL != target)
	{
		printk("      xt_target.name = %s\n", target->name);
		printk("      xt_target.revision = %d\n", target->revision);
		printk("      xt_target.table = %s\n", target->table);
		printk("      xt_target.targetsize = %d\n", target->targetsize);
		printk("      xt_target.usersize = %d\n", target->usersize);
		printk("      xt_target.hooks = %d\n", target->hooks);
		printk("      xt_target.proto = %d\n", target->proto);
		printk("      xt_target.family = %d\n", target->family);
	}
	... ...
}更新驱动,调用用户空间测试程序,最后用iptables查下INPUT链的配置,查询结果如下:
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT tcp -- 1.2.3.5 0.0.0.0/0
ACCEPT all -- !1.2.3.4 0.0.0.0/0
由此可见,上述代码的改动,已经生效了。



















