分类: LINUX
2010-01-22 16:55:33
本章主要是讲iptables命令的整个处理过程,包括:
1. 命令行参数解析;
2. 从kernel取得初始规则集;
3. 显示规则;或如果要设置,那么组装要发送到kernel的数据结构;
4. 发送到kernel;
TC_HANDLE_T
TC_INIT(const char *tablename)
它根据表名,从内核获取对应的表的相关信息
{
TC_HANDLE_T h; // iptables操作的结构体,下面解释
STRUCT_GETINFO info; // 用于存储从内核返回的信息,下面解释
unsigned int tmp;
socklen_t s;
iptc_fn = TC_INIT;
if (strlen(tablename) >= TABLE_MAXNAMELEN) {
errno = EINVAL;
return NULL;
}
if (sockfd_use == 0) {
sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW);
if (sockfd < 0)
return NULL;
}
sockfd_use++;
s = sizeof(info);
strcpy(info.name, tablename); // 表名
if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0) { // 从内核获取info信息
if (--sockfd_use == 0) {
close(sockfd);
sockfd = -1;
}
return NULL;
}
DEBUGP("valid_hooks=0x%08x, num_entries=%u, size=%u\n",
info.valid_hooks, info.num_entries, info.size);
if ((h = alloc_handle(info.name, info.size, info.num_entries))
参数: 表名;规则总大小;规则总数(在上面的getsockopt中获得)
分配TC_HANDLE_T,参考下面解释
== NULL) {
if (--sockfd_use == 0) {
close(sockfd);
sockfd = -1;
}
return NULL;
}
/* Initialize current state */
h->info = info; // 赋值内核空间得到的info
h->entries->size = h->info.size;
tmp = sizeof(STRUCT_GET_ENTRIES) + h->info.size; // tmp是STRUCT_GET_ENTRIES
// 连同尾巴的大小
if (getsockopt(sockfd, TC_IPPROTO, SO_GET_ENTRIES, h->entries,
&tmp) < 0) // 获得STRUCT_GET_ENTRIES信息,参考下面
goto error;
#ifdef IPTC_DEBUG2
{
int fd = open("/tmp/libiptc-so_get_entries.blob",
O_CREAT|O_WRONLY);
if (fd >= 0) {
write(fd, h->entries, tmp);
close(fd);
}
}
#endif
if (parse_table(h) < 0) // chain是只存在用户空间的,都是在这里解析得到的。
goto error; // 此函数后面说明
CHECK(h);
return h;
error:
if (--sockfd_use == 0) {
close(sockfd);
sockfd = -1;
}
TC_FREE(&h);
return NULL;
}
Libiptc.h:
/* Transparent handle type. */
typedef struct iptc_handle *iptc_handle_t;
Libip4tc.c
#define STRUCT_TC_HANDLE struct iptc_handle
Libiptc.c
STRUCT_TC_HANDLE
{
int changed; /* Have changes been made? */
struct list_head chains;
struct chain_head *chain_iterator_cur;
struct rule_head *rule_iterator_cur;
STRUCT_GETINFO info; // 下面解释
STRUCT_GET_ENTRIES *entries; // 下面解释
};
Libip4tc.c
#define STRUCT_GETINFO struct ipt_getinfo
Kernel:
/* The argument to IPT_SO_GET_INFO */
struct ipt_getinfo // 和struct xt_table_info很像
{
/* Which table: caller fills this in. */
char name[IPT_TABLE_MAXNAMELEN]; // 表名
/* Kernel fills these in. */
/* Which hook entry points are valid: bitmask */
unsigned int valid_hooks;
/* Hook entry points: one per netfilter hook. */
unsigned int hook_entry[NF_IP_NUMHOOKS];
/* Underflow points. */
unsigned int underflow[NF_IP_NUMHOOKS];
/* Number of entries */
unsigned int num_entries;
/* Size of entries. */
unsigned int size;
};
Libip4tc.c
#define STRUCT_GET_ENTRIES struct ipt_get_entries
Kernel:
/* The argument to IPT_SO_GET_ENTRIES. */
struct ipt_get_entries // 感觉像控制一个表里所有的ipt_entry的一个结构体
{
/* Which table: user fills this in. */
char name[IPT_TABLE_MAXNAMELEN];
/* User fills this in: total entry size. */
unsigned int size; // 所有下面的ipt_entry结构体的大小
/* The entries. */
struct ipt_entry entrytable[0]; // 所有的ipt_entry结构体
};
/* This structure defines each of the firewall rules. Consists of 3
parts which are 1) general IP header stuff 2) match specific
stuff 3) the target to perform if the rule matches */
struct ipt_entry
{
struct ipt_ip ip;
/* Mark with fields that we care about. */
unsigned int nfcache;
/* Size of ipt_entry + matches */
u_int16_t target_offset;
/* Size of ipt_entry + matches + target */
u_int16_t next_offset;
/* Back pointer */
unsigned int comefrom;
/* Packet and byte counters. */
struct xt_counters counters;
/* The matches (if any), then the target. */
unsigned char elems[0];
};
/* Allocate handle of given size */
static TC_HANDLE_T
alloc_handle(const char *tablename, unsigned int size, unsigned int num_rules)
参数: 表名;所有规则的大小;规则的总数
就做了个根据size申请空间的工作。
{
size_t len;
TC_HANDLE_T h;
len = sizeof(STRUCT_TC_HANDLE) + size; // 下面没用到
h = malloc(sizeof(STRUCT_TC_HANDLE)); // 申请空间
if (!h) {
errno = ENOMEM;
return NULL;
}
memset(h, 0, sizeof(*h));
INIT_LIST_HEAD(&h->chains); // alloc_handle才初始化,也就是说chain是只存在于user空间的
strcpy(h->info.name, tablename); // STRUCT_GETINFO info中设置表名
// 多余,因为出去此函数有h->info = info;
h->entries = malloc(sizeof(STRUCT_GET_ENTRIES) + size); // 控制ipt_entry以及所有ipt_entry
if (!h->entries) // 申请它本身的大小,并且要申请尾巴上的entrytable[0]的大小
goto out_free_handle;
strcpy(h->entries->name, tablename); // STRUCT_GET_ENTRIES *entries中设置表名
h->entries->size = size; // STRUCT_GET_ENTRIES *entries中设置设置大小
// 多余,因为出去此函数有h->entries->size = h->info.size;
return h;
out_free_handle:
free(h);
return NULL;
}
/* Creates a new chain. */
/* To create a chain, create two rules: error node and unconditional
* return. */
啥意思,没看懂。似乎这个链初始化函数并没有做这个事情,只是调用了
int
TC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
分配一个chain_head,然后挂接到(*handle)->chains链表后面去。
说明自定义链是在标准链的后面。
{
static struct chain_head *c; // 下面解释
iptc_fn = TC_CREATE_CHAIN;
/* find_label doesn't cover built-in targets: DROP, ACCEPT,
QUEUE, RETURN. */
if (iptcc_find_label(chain, *handle) // 查询此chain是否已经注册,下面解释
|| strcmp(chain, LABEL_DROP) == 0 // #define IPTC_LABEL_ACCEPT "ACCEPT"
|| strcmp(chain, LABEL_ACCEPT) == 0
|| strcmp(chain, LABEL_QUEUE) == 0
|| strcmp(chain, LABEL_RETURN) == 0) {
DEBUGP("Chain `%s' already exists\n", chain);
errno = EEXIST;
return 0;
}
if (strlen(chain)+1 > sizeof(IPT_CHAINLABEL)) { // 链名过长
DEBUGP("Chain name `%s' too long\n", chain);
errno = EINVAL;
return 0;
}
c = iptcc_alloc_chain_head(chain, 0); // 分配一个chain_head,函数下面解释
if (!c) {
DEBUGP("Cannot allocate memory for chain `%s'\n", chain);
errno = ENOMEM;
return 0;
}
DEBUGP("Creating chain `%s'\n", chain);
list_add_tail(&c->list, &(*handle)->chains); // 挂接到(*handle)->chains链表的后面去
set_changed(*handle); // 设置h->changed = 1;
return 1;
}
struct chain_head
{
struct list_head list; // 挂接在&handle->chains
char name[TABLE_MAXNAMELEN]; // 名字
unsigned int hooknum; /* hook number+1 if builtin */
unsigned int references; /* how many jumps reference us */
int verdict; /* verdict if builtin */
STRUCT_COUNTERS counters; /* per-chain counters */
struct counter_map counter_map;
unsigned int num_rules; /* number of rules in list */
struct list_head rules; /* list of rules */ // 链的规则,下面
unsigned int index; /* index (needed for jump resolval) */
unsigned int head_offset; /* offset in rule blob */
unsigned int foot_index; /* index (needed for counter_map) */
unsigned int foot_offset; /* offset in rule blob */
};
struct rule_head
{
struct list_head list;
struct chain_head *chain;
struct counter_map counter_map;
unsigned int index; /* index (needed for counter_map) */
unsigned int offset; /* offset in rule blob */
enum iptcc_rule_type type;
struct chain_head *jump; /* jump target, if IPTCC_R_JUMP */
unsigned int size; /* size of entry data */
STRUCT_ENTRY entry[0]; // 具体entry
};
/* Returns chain head if found, otherwise NULL. */
static struct chain_head *
iptcc_find_label(const char *name, TC_HANDLE_T handle)
{
struct list_head *pos;
if (list_empty(&handle->chains))
return NULL;
list_for_each(pos, &handle->chains) { // 对handle->chains进行遍历
struct chain_head *c = list_entry(pos, struct chain_head, list);
if (!strcmp(c->name, name)) // 如果名字相等
return c; // 则认为找到,返回找到的chain
}
return NULL;
}
/* allocate a new chain head for the cache */
static struct chain_head *iptcc_alloc_chain_head(const char *name, int hooknum)
{
struct chain_head *c = malloc(sizeof(*c));
if (!c)
return NULL;
memset(c, 0, sizeof(*c)); // 分配空间并初始化全0
strncpy(c->name, name, TABLE_MAXNAMELEN); // 设置链名为name
c->hooknum = hooknum; // 设置chain_head里面的hooknum
INIT_LIST_HEAD(&c->rules); // 初始化chain_head里面的rules
return c;
}
static int
(const ipt_chainlabel chain, int verbose, int numeric,
int expanded, int linenumbers, iptc_handle_t *handle)
chain为制定的链名;
{
int found = 0;
unsigned int format;
const char *this;
format = FMT_OPTIONS;
if (!verbose)
format |= FMT_NOCOUNTS;
else
format |= FMT_VIA;
if (numeric)
format |= FMT_NUMERIC;
if (!expanded)
format |= FMT_KILOMEGAGIGA;
if (linenumbers)
format |= FMT_LINENUMBERS;
for (this = iptc_first_chain(handle); // 取得第一个链并返回链名,下面解释
this;
this = iptc_next_chain(handle)) {
const struct ipt_entry *i;
unsigned int num;
if (chain && strcmp(chain, this) != 0) // 如果指定了链名chain,那么就要寻找指定的
continue;
if (found) printf("\n");
print_header(format, this, handle); // 输出头部
i = iptc_first_rule(this, handle); // 找到指定chain(名)的第一个规则
num = 0;
while (i) {
print_firewall(i, // 下面详细讲
iptc_get_target(i, handle), // 获得target的名字
num++,
format,
*handle);
i = iptc_next_rule(i, handle); // 参考后面
}
found = 1;
}
errno = ENOENT;
return found;
}
/* Iterator functions to run through the chains. */
const char *
TC_FIRST_CHAIN(TC_HANDLE_T *handle)
{
struct chain_head *c = list_entry((*handle)->chains.next,
struct chain_head, list); // 第一个chain_head
iptc_fn = TC_FIRST_CHAIN;
if (list_empty(&(*handle)->chains)) {
DEBUGP(": no chains\n");
return NULL;
}
(*handle)->chain_iterator_cur = c; // 赋值给(*handle)->chain_iterator_cur
iptcc_chain_iterator_advance(*handle); // 更新handle->chain_iterator_cur
DEBUGP(": returning `%s'\n", c->name);
return c->name; // 返回链名字
}
/* Get first rule in the given chain: NULL for empty chain. */
const STRUCT_ENTRY *
TC_FIRST_RULE(const char *chain, TC_HANDLE_T *handle)
chain:指定的链名
{
struct chain_head *c;
struct rule_head *r;
iptc_fn = TC_FIRST_RULE;
DEBUGP("first rule(%s): ", chain);
c = iptcc_find_label(chain, *handle); // 根据链名,找到链的结构体chain_head
if (!c) {
errno = ENOENT;
return NULL;
}
/* Empty chain: single return/policy rule */
if (list_empty(&c->rules)) { // 判断链是否有规则
DEBUGP_C("no rules, returning NULL\n");
return NULL;
}
r = list_entry(c->rules.next, struct rule_head, list); // 找到第一个rule_head
(*handle)->rule_iterator_cur = r; // 赋值给(*handle)->rule_iterator_cur
DEBUGP_C("%p\n", r);
return r->entry; // 返回entry
}