分类: LINUX
2010-01-22 16:58:45
本章主要是讲iptables命令的整个处理过程,包括:
1. 命令行参数解析;
2. 从kernel取得初始规则集;
3. 显示规则;或如果要设置,那么组装要发送到kernel的数据结构;
4. 发送到kernel;
/* Append entry `fw' to chain `chain'. Equivalent to insert with
rulenum = length of chain. */
int
TC_APPEND_ENTRY(const IPT_CHAINLABEL chain,
const STRUCT_ENTRY *e,
TC_HANDLE_T *handle)
{
struct chain_head *c;
struct rule_head *r;
iptc_fn = TC_APPEND_ENTRY;
if (!(c = iptcc_find_label(chain, *handle))) { // 确认chain是否存在
DEBUGP("unable to find chain `%s'\n", chain);
errno = ENOENT;
return 0;
}
if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
DEBUGP("unable to allocate rule for chain `%s'\n", chain);
errno = ENOMEM;
return 0;
}
memcpy(r->entry, e, e->next_offset);
r->counter_map.maptype = COUNTER_MAP_SET;
if (!iptcc_map_target(*handle, r)) { // 这个函数很重要。似乎是修改r中的target
DEBUGP("unable to map target of rule for chain `%s'\n", chain);
free(r);
return 0;
}
list_add_tail(&r->list, &c->rules); // 添加到chain的rules链的尾部
c->num_rules++;
set_changed(*handle);
return 1;
}
static int iptcc_compile_table(TC_HANDLE_T h, STRUCT_REPLACE *repl)
{
struct chain_head *c;
struct iptcb_chain_error *error;
struct iptcb_chain_error {
STRUCT_ENTRY entry;
struct ipt_error_target target;
};
/* Second pass: copy from cache to offsets, fill in jumps */
list_for_each_entry(c, &h->chains, list) { // 顺序处理每条链。链按照类型排序是:
int ret = iptcc_compile_chain(h, repl, c);
if (ret < 0)
return ret;
}
/* Append error rule at end of chain */ // 貌似最后加个
error = (void *)repl->entries + repl->size - IPTCB_CHAIN_ERROR_SIZE;
这个size是等于多少?
error->entry.target_offset = sizeof(STRUCT_ENTRY);
error->entry.next_offset = IPTCB_CHAIN_ERROR_SIZE;
error->target.t.u.user.target_size =
ALIGN(sizeof(struct ipt_error_target));
strcpy((char *)&error->target.t.u.user.name, ERROR_TARGET);// ERROR_TARGET = “ERROR”
strcpy((char *)&error->target.error, "ERROR"); // error->target.error也设置为"ERROR"
return 1;
}
/* compile chain from cache into blob */
static int iptcc_compile_chain(TC_HANDLE_T h, STRUCT_REPLACE *repl, struct chain_head *c)
在这里会构筑blob的链;
找了半天的链头的ERROR_TARGET的规则就是在这里被加入的。
{
int ret;
struct rule_head *r;
struct iptcb_chain_start *head;
struct iptcb_chain_foot *foot;
/* only user-defined chains have heaer */
if (!iptcc_is_builtin(c)) { // 如果不是内建链的话(return (c->hooknum ? 1 : 0);)
/* put chain header in place */ // 在c->head_offset处,设置一个iptcb_chain_start *head;
head = (void *)repl->entries + c->head_offset;
head->e.target_offset = sizeof(STRUCT_ENTRY);
head->e.next_offset = IPTCB_CHAIN_START_SIZE;
strcpy(head->name.t.u.user.name, ERROR_TARGET); // ERROR_TARGET = “ERROR”
head->name.t.u.target_size =
ALIGN(sizeof(struct ipt_error_target));
strcpy(head->name.error, c->name); // 这个地方的name是链名
/* Convenience structures */
struct iptcb_chain_start{
STRUCT_ENTRY e;
struct ipt_error_target name;
};
/* Convenience structures */
struct ipt_error_target
{
STRUCT_ENTRY_TARGET t;
char error[TABLE_MAXNAMELEN];
} else {
repl->hook_entry[c->hooknum-1] = c->head_offset; // 如果不是自定义链,那么记录
repl->underflow[c->hooknum-1] = c->foot_offset; // hook_entry和underflow
}
/* iterate over rules */
list_for_each_entry(r, &c->rules, list) {
ret = iptcc_compile_rule(h, repl, r);
if (ret < 0)
return ret;
}
/* put chain footer in place */ // 每个链都会有这个处理,加个链的footer
foot = (void *)repl->entries + c->foot_offset;
foot->e.target_offset = sizeof(STRUCT_ENTRY);
foot->e.next_offset = IPTCB_CHAIN_FOOT_SIZE; // STRUCT_STANDARD_TARGET
strcpy(foot->target.target.u.user.name, STANDARD_TARGET);
foot->target.target.u.target_size =
ALIGN(sizeof(STRUCT_STANDARD_TARGET));
/* builtin targets have verdict, others return */
if (iptcc_is_builtin(c))
foot->target.verdict = c->verdict; // 内建链设置target.verdict = c->verdict
else
foot->target.verdict = RETURN; // 自定义链设置target.verdict = RETURN
/* set policy-counters */
memcpy(&foot->e.counters, &c->counters, sizeof(STRUCT_COUNTERS));
return 0;
}
/* compile rule from cache into blob */
static inline int iptcc_compile_rule (TC_HANDLE_T h, STRUCT_REPLACE *repl, struct rule_head *r)
{
/* handle jumps */
if (r->type == IPTCC_R_JUMP) {
STRUCT_STANDARD_TARGET *t;
t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
/* memset for memcmp convenience on delete/replace */
memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN);
strcpy(t->target.u.user.name, STANDARD_TARGET);
/* Jumps can only happen to builtin chains, so we
* can safely assume that they always have a header */
t->verdict = r->jump->head_offset + IPTCB_CHAIN_START_SIZE;
如果是一条类型为IPTCC_R_JUMP的规则,那么设置对应的blob内的规则的verdict为所跳转的链的第二条规则(的偏移)。非内建链的第一条规则必须是一条iptcb_chain_start规则,参考iptcc_compile_chain()
STRUCT_STANDARD_TARGET是内核定义的结构体:
struct xt_standard_target
{
struct xt_entry_target target;
int verdict;
};
} else if (r->type == IPTCC_R_FALLTHROUGH) {
STRUCT_STANDARD_TARGET *t;
t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
t->verdict = r->offset + r->size;
}
/* copy entry from cache to blob */
memcpy((char *)repl->entries+r->offset, r->entry, r->size); // 看到了规则的拷贝
return 1;
}