修改《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
由此可见,上述代码的改动,已经生效了。