iptables 流程分析(ip6tables同理)
iptables 作为接口开机并不启动在执行命令才开始启动,所以在系统进程看不到此进程。
https://wiki.archlinuxcn.org/wiki/Iptables?rdfrom=https%3A%2F%2Fwiki.archlinux.org%2Findex.php%3Ftitle%3DIptables_%28%25E7%25AE%2580%25E4%25BD%2593%25E4%25B8%25AD%25E6%2596%2587%29%26redirect%3Dno
一. iptables 入口函数:
1. BIN 文件入口:
文件:iptables/xtables-multi.c
static const struct subcommand multi_subcommands[] = {
#ifdef ENABLE_IPV4
{"iptables", iptables_main},
{"main4", iptables_main},
{"iptables-save", iptables_save_main},
{"save4", iptables_save_main},
{"iptables-restore", iptables_restore_main},
{"restore4", iptables_restore_main},
#endif
......
}
int main(int argc, char **argv)
{
return subcmd_main(argc, argv, multi_subcommands);
}
2. 命令入口:
文件:iptables/iptables-standalone.c
int iptables_main(int argc, char *argv[])
{
return xtables_main(NFPROTO_IPV4, "iptables", argc, argv);
}
调用xtables_main过滤执行命令,在进入到xtables_main中会先加载规则,然后过滤输入参数,若参数无误则设置到netfilter中处理,xtables_main方法如下:
int iptables_main(int argc, char *argv[]) {
int ret;
char *table = "filter";
struct xtc_handle *handle = NULL;
signal(SIGPIPE, SIG_IGN);
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);
}
二. 命令解析
1. 过滤参数do_commandx
文件:iptables/iptables.c
方法:do_command4 ,使用getopt_long方法解析输入参数。getopt_long方法参考:https://blog.csdn.net/ljl113/article/details/131398079
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;
......
}
测试如下:
iptables -A OUTPUT -m owner --pid-owner 78
param 0 : iptables
param 1 : -A
iptables param 2 : OUTPUT
iptables param 3 : -m
iptables param 4 : owner
iptables param 5 : --pid-owner
iptables param 6 : 78
do_command4 拆解参数后执行命令iptc_commit命令
//执行如下
ret = iptc_commit(handle);
iptc_free(handle);
//解析xt参数 如:iptables -A OUTPUT -m owner --uid-owner 1000 -j ACCEPT 中的“ -uid-owner 1000”
//查找解析对象 xtables_match
//文件:libxtables/xtables.c
xtables_find_match(const char *name, enum xtables_tryload tryload,struct xtables_rule_match **matches)
iptc_commit方法
//文件:libiptc/libip4tc.c
#define TC_COMMIT iptc_commit
//libiptc/libiptc.c
int TC_COMMIT(struct xtc_handle *handle)
add_command
大写字母: 视为命令 调用add_command函数将其加入command 变量中
小写字母: 视为OPtion, 调用set_option函数将其加入options变量中, 并更新 &fw.ip.invflags 变量, 表明是否是一个反转option