修改《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");}// 有matchif (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
由此可见,上述代码的改动,已经生效了。