分类: LINUX
2016-11-20 17:12:17
/net/ipv4/netfilter/ip_table.c
static int do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
{
int ret;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
switch (cmd) {
/*iptable下发rule使用该命令字*/
case IPT_SO_SET_REPLACE:
ret = do_replace(sock_net(sk), user, len);
break;
}
......
return ret;
}
static int do_replace(struct net *net, void __user *user, unsigned int len)static int translate_table(const char *name,
unsigned int valid_hooks,
struct xt_table_info *newinfo,
void *entry0,
unsigned int size,
unsigned int number,
const unsigned int *hook_entries,
const unsigned int *underflows)
{
unsigned int i;
int ret;
/*初始化xt_table_info一些字段*/
newinfo->size = size;
newinfo->number = number;
/* Init all hooks to impossible value. */
for (i = 0; i < NF_INET_NUMHOOKS; i++) {
newinfo->hook_entry[i] = 0xFFFFFFFF;
newinfo->underflow[i] = 0xFFFFFFFF;
}
。。。。。。
i = 0;
/* Walk through entries, checking offsets. */
/*遍历该table下所有的chain中的所有rule,进行检查并初始化
xt_table_info的hook_entries和underflows。*/
ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
check_entry_size_and_hooks,
newinfo,
entry0,
entry0 + size,
hook_entries, underflows, valid_hooks, &i);
。。。。。。
if (!mark_source_chains(newinfo, valid_hooks, entry0))
return -ELOOP;
/* Finally, each sanity check must pass */
i = 0;
/*遍历table下的所有chain下的所有rule,
调用find_check_entry进行rule的检查和转换成内核rule*/
ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
find_check_entry, name, size, &i);
。。。。。。
/*把转换好的本地CPU上的rule给每个cpu拷贝一份*/
/* And one copy for every other CPU */
for_each_possible_cpu(i) {
if (newinfo->entries[i] && newinfo->entries[i] != entry0)
memcpy(newinfo->entries[i], entry0, newinfo->size);
}
return ret;
}
static int find_check_entry(struct ipt_entry *e, const char *name, unsigned int size,
unsigned int *i)
{
struct ipt_entry_target *t;
struct xt_target *target;
int ret;
unsigned int j;
struct xt_mtchk_param mtpar;
ret = check_entry(e, name);
if (ret)
return ret;
j = 0;
mtpar.table = name;
mtpar.entryinfo = &e->ip;
mtpar.hook_mask = e->comefrom;
mtpar.family = NFPROTO_IPV4;
/*把rule中存在的扩展match,从名字转换为内核指针*/
ret = IPT_MATCH_ITERATE(e, find_check_match, &mtpar, &j);
if (ret != 0)
goto cleanup_matches;
t = ipt_get_target(e);
/*把rule中存在的扩展target,从名字转换为内核指针*/
target = try_then_request_module(xt_find_target(AF_INET,
t->u.user.name,
t->u.user.revision),
"ipt_%s", t->u.user.name);
if (IS_ERR(target) || !target) {
duprintf("find_check_entry: `%s' not found\n", t->u.user.name);
ret = target ? PTR_ERR(target) : -ENOENT;
goto cleanup_matches;
}
t->u.kernel.target = target;
ret = check_target(e, name);
if (ret)
goto err;
(*i)++;
return 0;
err:
module_put(t->u.kernel.target->me);
cleanup_matches:
IPT_MATCH_ITERATE(e, cleanup_match, &j);
return ret;
}
Netfilter把rule的排序由配置工具来管理和完成,每次使用iptable下发一条rule时,iptable首先要从内核中把对应表的所有rule到拷贝一份到用户空间,然后再把新的rule插入,然后排序后再下发到内核中,替换表中旧的rule。
这样如果在已存在大量rule的情况下,使用iptable下发一条rule时,速度是很慢的。
(未完待续)