Chinaunix首页 | 论坛 | 博客
  • 博客访问: 107744
  • 博文数量: 41
  • 博客积分: 2520
  • 博客等级: 少校
  • 技术积分: 440
  • 用 户 组: 普通用户
  • 注册时间: 2010-01-22 16:25
文章分类

全部博文(41)

文章存档

2010年(41)

我的朋友

分类: 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;    // tmpSTRUCT_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. */

啥意思,没看懂。似乎这个链初始化函数并没有做这个事情,只是调用了

iptcc_alloc_chain_head() -> INIT_LIST_HEAD(&c->rules);

似乎是cache -> blob是对自定义链,会有这个处理。

下面看了再解释。。。

 

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

}

 

阅读(672) | 评论(0) | 转发(0) |
0

上一篇:iptables (2)

下一篇:iptables (4)

给主人留下些什么吧!~~