由于我们只关注ipv4.
看程序的流程就是要从主线开始看起。
目录结构我
libiptc:iptables控制层代码
iptables:iptables主体代码
extensions:iptables扩展代码,一般是xtables_register_matches函数注册被初始化的struct xtables_match结构体
我执行的iptables命令是 iptables -A INPUT -p tcp --dport 443 -m set --match-set myhash src -j DROP
iptables_main函数是主函数
位于iptables_standalone.c文件中
int
iptables_main(int argc, char *argv[])
{
int ret;
//默认表是filter
char *table = "filter";
struct xtc_handle *handle = NULL;
iptables_globals.program_name = "iptables";
ret = xtables_init_all(&iptables_globals, NFPROTO_IPV4);
if (ret < 0) {
fprintf(stderr, "%s/%s Failed to initialize xtables\n",
iptables_globals.program_name,
iptables_globals.program_version);
exit(1);
}
#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
init_extensions();
init_extensions4();
#endif
ret = do_command4(argc, argv, &table, &handle, false);
if (ret) {
ret = iptc_commit(handle);
iptc_free(handle);
}
if (!ret) {
if (errno == EINVAL) {
fprintf(stderr, "iptables: %s. "
"Run `dmesg' for more information.\n",
iptc_strerror(errno));
} else {
fprintf(stderr, "iptables: %s.\n",
iptc_strerror(errno));
}
if (errno == EAGAIN) {
exit(RESOURCE_PROBLEM);
}
}
exit(!ret);
}
iptables很多东东,是用共享库*.so的形式来提供的,如果不采用共享库,则进行一个初始化操作。
iptables默认是采用共享库的,因此忽略它。
do_command4函数
do_command4 函数是整个系统的核心,负责处理整个用户的输入命令。
因函数代码太长,所以我只截取其中一段代码,
while ((cs.c = getopt_long(argc, argv,
"-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvw::W::nt:m:xc:g:46",
opts, NULL)) != -1) {
switch (cs.c) {
/*
* Command selection
*/
case 'A':
add_command(&command, CMD_APPEND, CMD_NONE,
cs.invert);
chain = optarg;
break;
case 'C':
add_command(&command, CMD_CHECK, CMD_NONE,
cs.invert);
chain = optarg;
break;
case 'D':
add_command(&command, CMD_DELETE, CMD_NONE,
cs.invert);
chain = optarg;
if (xs_has_arg(argc, argv)) {
rulenum = parse_rulenumber(argv[optind++]);
command = CMD_DELETE_NUM;
}
break;
case 'R':
add_command(&command, CMD_REPLACE, CMD_NONE,
cs.invert);
chain = optarg;
if (xs_has_arg(argc, argv))
rulenum = parse_rulenumber(argv[optind++]);
else
xtables_error(PARAMETER_PROBLEM,
"-%c requires a rule number",
cmd2char(CMD_REPLACE));
break;
case 'I':
add_command(&command, CMD_INSERT, CMD_NONE,
cs.invert);
chain = optarg;
if (xs_has_arg(argc, argv))
rulenum = parse_rulenumber(argv[optind++]);
else rulenum = 1;
break;
函数首先对一些结构、变量进行初始化,初始化完毕后,进入while循环,解析用户输入的命令(如增删改查命令),设置相关的标志变量,然后根据相应标志,调用对应的处理函数。
其中的标志(-A,-C,-D,-I,-R,-L)对应iptables命令如下
以-A参数举例,其调用add_command函数,函数参数是CMD_APPEND命令
case 'A':
add_command(&command, CMD_APPEND, CMD_NONE,
cs.invert);
chain = optarg;
break;
将CMD_APPEND保存到command变量中,将选择的挂载点保存在chain变量中
如果do_command4函数返回值为true,则调用iptc_commit 执行规则的改变
全局搜索后,并没有搜索到iptc_commit函数的实现,只在libip4tc.c文件中搜索到
#define TC_COMMIT iptc_commit
转而继续搜索 TC_COMMIT
TC_COMMIT(struct xtc_handle *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)
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);
if (!repl) {
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->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);
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, 0644);
if (fd >= 0) {
write(fd, repl, sizeof(*repl) + repl->size);
close(fd);
}
}
#endif
ret = setsockopt(handle->sockfd, TC_IPPROTO, SO_SET_REPLACE, repl,
sizeof(*repl) + repl->size);
if (ret < 0)
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 IPTC_DEBUG2
{
int fd = open("/tmp/libiptc-so_set_add_counters.blob",
O_CREAT|O_WRONLY, 0644);
if (fd >= 0) {
write(fd, newcounters, counterlen);
close(fd);
}
}
#endif
ret = setsockopt(handle->sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS,
newcounters, counterlen);
if (ret < 0)
goto out_free_newcounters;
free(repl->counters);
free(repl);
free(newcounters);
finished:
return 1;
out_free_newcounters:
free(newcounters);
out_free_repl_counters:
free(repl->counters);
out_free_repl:
free(repl);
out_zero:
return 0;
}