分类: LINUX
2010-01-22 16:58:06
本章主要是讲iptables命令的整个处理过程,包括:
1. 命令行参数解析;
2. 从kernel取得初始规则集;
3. 显示规则;或如果要设置,那么组装要发送到kernel的数据结构;
4. 发送到kernel;
int
TC_COMMIT(TC_HANDLE_T *handle)
{
/* Replace, then map back the counters. */
STRUCT_REPLACE *repl;
STRUCT_COUNTERS_INFO *newcounters;
struct chain_head *c;
int ret;
size_t counterlen;
int new_number;
unsigned int new_size;
iptc_fn = TC_COMMIT;
CHECK(*handle);
/* Don't commit if nothing changed. */
if (!(*handle)->changed) // 有变化才需要提交kernel
goto finished;
new_number = iptcc_compile_table_prep(*handle, &new_size);
if (new_number < 0) {
errno = ENOMEM;
goto out_zero;
}
repl = malloc(sizeof(*repl) + new_size); // 申请repl
if (!repl) { // #define STRUCT_REPLACE struct ipt_replace
errno = ENOMEM;
goto out_zero;
}
memset(repl, 0, sizeof(*repl) + new_size);
#if 0
TC_DUMP_ENTRIES(*handle);
#endif
counterlen = sizeof(STRUCT_COUNTERS_INFO)
+ sizeof(STRUCT_COUNTERS) * new_number;
/* These are the old counters we will get from kernel */
repl->counters = malloc(sizeof(STRUCT_COUNTERS)
* (*handle)->info.num_entries);
if (!repl->counters) {
errno = ENOMEM;
goto out_free_repl;
}
/* These are the counters we're going to put back, later. */
newcounters = malloc(counterlen);
if (!newcounters) {
errno = ENOMEM;
goto out_free_repl_counters;
}
memset(newcounters, 0, counterlen);
strcpy(repl->name, (*handle)->info.name); // repl的设置
repl->num_entries = new_number;
repl->size = new_size;
repl->num_counters = (*handle)->info.num_entries;
repl->valid_hooks = (*handle)->info.valid_hooks;
DEBUGP("num_entries=%u, size=%u, num_counters=%u\n",
repl->num_entries, repl->size, repl->num_counters);
ret = iptcc_compile_table(*handle, repl); // 根据*handle来构成repl的规则部分
if (ret < 0) {
errno = ret;
goto out_free_newcounters;
}
#ifdef IPTC_DEBUG2
{
int fd = open("/tmp/libiptc-so_set_replace.blob",
O_CREAT|O_WRONLY);
if (fd >= 0) {
write(fd, repl, sizeof(*repl) + repl->size);
close(fd);
}
}
#endif
ret = setsockopt(sockfd, TC_IPPROTO, SO_SET_REPLACE, repl, // 向内核发出请求
sizeof(*repl) + repl->size); // 重要的就成了看repl的组织
if (ret < 0) { // 注意规则要贴在ipt_replace的后面
errno = ret;
goto out_free_newcounters;
}
/* Put counters back. */
strcpy(newcounters->name, (*handle)->info.name);
newcounters->num_counters = new_number;
list_for_each_entry(c, &(*handle)->chains, list) {
struct rule_head *r;
/* Builtin chains have their own counters */
if (iptcc_is_builtin(c)) {
DEBUGP("counter for chain-index %u: ", c->foot_index);
switch(c->counter_map.maptype) {
case COUNTER_MAP_NOMAP:
counters_nomap(newcounters, c->foot_index);
break;
case COUNTER_MAP_NORMAL_MAP:
counters_normal_map(newcounters, repl,
c->foot_index,
c->counter_map.mappos);
break;
case COUNTER_MAP_ZEROED:
counters_map_zeroed(newcounters, repl,
c->foot_index,
c->counter_map.mappos,
&c->counters);
break;
case COUNTER_MAP_SET:
counters_map_set(newcounters, c->foot_index,
&c->counters);
break;
}
}
list_for_each_entry(r, &c->rules, list) {
DEBUGP("counter for index %u: ", r->index);
switch (r->counter_map.maptype) {
case COUNTER_MAP_NOMAP:
counters_nomap(newcounters, r->index);
break;
case COUNTER_MAP_NORMAL_MAP:
counters_normal_map(newcounters, repl,
r->index,
r->counter_map.mappos);
break;
case COUNTER_MAP_ZEROED:
counters_map_zeroed(newcounters, repl,
r->index,
r->counter_map.mappos,
&r->entry->counters);
break;
case COUNTER_MAP_SET:
counters_map_set(newcounters, r->index,
&r->entry->counters);
break;
}
}
}
#ifdef KERNEL_64_USERSPACE_32
{
/* Kernel will think that pointer should be 64-bits, and get
padding. So we accomodate here (assumption: alignment of
`counters' is on 64-bit boundary). */
u_int64_t *kernptr = (u_int64_t *)&newcounters->counters;
if ((unsigned long)&newcounters->counters % 8 != 0) {
fprintf(stderr,
"counters alignment incorrect! Mail rusty!\n");
abort();
}
*kernptr = newcounters->counters;
}
#endif /* KERNEL_64_USERSPACE_32 */
#ifdef IPTC_DEBUG2
{
int fd = open("/tmp/libiptc-so_set_add_counters.blob",
O_CREAT|O_WRONLY);
if (fd >= 0) {
write(fd, newcounters, counterlen);
close(fd);
}
}
#endif
ret = setsockopt(sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS,
newcounters, counterlen);
if (ret < 0) {
errno = ret;
goto out_free_newcounters;
}
free(repl->counters);
free(repl);
free(newcounters);
finished:
TC_FREE(handle);
return 1;
out_free_newcounters:
free(newcounters);
out_free_repl_counters:
free(repl->counters);
out_free_repl:
free(repl);
out_zero:
return 0;
}
/* parse an iptables blob into it's pieces */
static int parse_table(TC_HANDLE_T h)
将TC_HANDLE_T的entries的规则解析到各个chain去
{
STRUCT_ENTRY *prev;
unsigned int num = 0;
struct chain_head *c;
/* First pass: over ruleset blob */
ENTRY_ITERATE(h->entries->entrytable, h->entries->size,
cache_add_entry, h, &prev, &num);
/* Second pass: fixup parsed data from first pass */
list_for_each_entry(c, &h->chains, list) {
struct rule_head *r;
list_for_each_entry(r, &c->rules, list) {
struct chain_head *c;
STRUCT_STANDARD_TARGET *t;
if (r->type != IPTCC_R_JUMP)
continue;
t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
c = iptcc_find_chain_by_offset(h, t->verdict);
if (!c)
return -1;
r->jump = c;
c->references++;
}
}
/* FIXME: sort chains */
return 1;
}
/* e is called `fw' here for hysterical raisins */
static void
print_firewall(const struct ipt_entry *fw,
const char *targname,
unsigned int num,
unsigned int format,
const iptc_handle_t handle)
{
struct iptables_target *target = NULL;
const struct ipt_entry_target *t;
u_int8_t flags;
char buf[BUFSIZ];
if (!iptc_is_chain(targname, handle))
target = find_target(targname, TRY_LOAD); // 根据名字找到target
else
target = find_target(IPT_STANDARD_TARGET, LOAD_MUST_SUCCEED);
t = ipt_get_target((struct ipt_entry *)fw);
flags = fw->ip.flags;
if (format & FMT_LINENUMBERS)
printf(FMT("%-4u ", "%u "), num+1);
if (!(format & FMT_NOCOUNTS)) {
print_num(fw->counters.pcnt, format);
print_num(fw->counters.bcnt, format);
}
if (!(format & FMT_NOTARGET))
printf(FMT("%-9s ", "%s "), targname);
fputc(fw->ip.invflags & IPT_INV_PROTO ? '!' : ' ', stdout);
{
char *pname = proto_to_name(fw->ip.proto, format&FMT_NUMERIC);
if (pname)
printf(FMT("%-5s", "%s "), pname);
else
printf(FMT("%-5hu", "%hu "), fw->ip.proto);
}
if (format & FMT_OPTIONS) {
if (format & FMT_NOTABLE)
fputs("opt ", stdout);
fputc(fw->ip.invflags & IPT_INV_FRAG ? '!' : '-', stdout);
fputc(flags & IPT_F_FRAG ? 'f' : '-', stdout);
fputc(' ', stdout);
}
if (format & FMT_VIA) {
char iface[IFNAMSIZ+2];
if (fw->ip.invflags & IPT_INV_VIA_IN) {
iface[0] = '!';
iface[1] = '\0';
}
else iface[0] = '\0';
if (fw->ip.iniface[0] != '\0') {
strcat(iface, fw->ip.iniface);
}
else if (format & FMT_NUMERIC) strcat(iface, "*");
else strcat(iface, "any");
printf(FMT(" %-6s ","in %s "), iface);
if (fw->ip.invflags & IPT_INV_VIA_OUT) {
iface[0] = '!';
iface[1] = '\0';
}
else iface[0] = '\0';
if (fw->ip.outiface[0] != '\0') {
strcat(iface, fw->ip.outiface);
}
else if (format & FMT_NUMERIC) strcat(iface, "*");
else strcat(iface, "any");
printf(FMT("%-6s ","out %s "), iface);
}
fputc(fw->ip.invflags & IPT_INV_SRCIP ? '!' : ' ', stdout);
if (fw->ip.smsk.s_addr ==
printf(FMT("%-19s ","%s "), "anywhere");
else {
if (format & FMT_NUMERIC)
sprintf(buf, "%s", addr_to_dotted(&(fw->ip.src)));
else
sprintf(buf, "%s", addr_to_anyname(&(fw->ip.src)));
strcat(buf, mask_to_dotted(&(fw->ip.smsk)));
printf(FMT("%-19s ","%s "), buf);
}
fputc(fw->ip.invflags & IPT_INV_DSTIP ? '!' : ' ', stdout);
if (fw->ip.dmsk.s_addr ==
printf(FMT("%-19s ","-> %s"), "anywhere");
else {
if (format & FMT_NUMERIC)
sprintf(buf, "%s", addr_to_dotted(&(fw->ip.dst)));
else
sprintf(buf, "%s", addr_to_anyname(&(fw->ip.dst)));
strcat(buf, mask_to_dotted(&(fw->ip.dmsk)));
printf(FMT("%-19s ","-> %s"), buf);
}
if (format & FMT_NOTABLE)
fputs(" ", stdout);
#ifdef IPT_F_GOTO
if(fw->ip.flags & IPT_F_GOTO)
printf("[goto] ");
#endif
IPT_MATCH_ITERATE(fw, print_match, &fw->ip, format & FMT_NUMERIC); // match的print
if (target) {
if (target->print)
/* Print the target information. */
target->print(&fw->ip, t, format & FMT_NUMERIC); // 调用target的用户定义的print()
} else if (t->u.target_size != sizeof(*t))
printf("[%u bytes of unknown target data] ",
(unsigned int)(t->u.target_size - sizeof(*t)));
if (!(format & FMT_NONEWLINE))
fputc('\n', stdout);
}
/* Returns NULL when rules run out. */
const STRUCT_ENTRY *
TC_NEXT_RULE(const STRUCT_ENTRY *prev, TC_HANDLE_T *handle)
{
struct rule_head *r;
iptc_fn = TC_NEXT_RULE;
DEBUGP("rule_iterator_cur=%p...", (*handle)->rule_iterator_cur);
if (!(*handle)->rule_iterator_cur) {
DEBUGP_C("returning NULL\n");
return NULL;
}
r = list_entry((*handle)->rule_iterator_cur->list.next,
struct rule_head, list);
iptc_fn = TC_NEXT_RULE;
DEBUGP_C("next=%p, head=%p...", &r->list,
&(*handle)->rule_iterator_cur->chain->rules);
if (&r->list == &(*handle)->rule_iterator_cur->chain->rules) {
(*handle)->rule_iterator_cur = NULL;
DEBUGP_C("finished, returning NULL\n");
return NULL;
}
(*handle)->rule_iterator_cur = r;
/* NOTE: prev is without any influence ! */
DEBUGP_C("returning rule %p\n", r);
return r->entry;
}