iptables源码分析(2)

1.1 表的查找

再回到iptc_init 函数上来,它根据表名,从内核获取对应的表的相关信息,handle是一个iptc_handle_t类型的指针,在libiptc.c中,有如下定义:

/* Transparent handle type. */

typedef struct iptc_handle *iptc_handle_t;

 

在Libip4tc中:

#define STRUCT_TC_HANDLE struct iptc_handle

在Libiptc.c中,可以找到STRUCT_TC_HANDLE的定义:

STRUCT_TC_HANDLE

{

/* Have changes been made? */

int changed;

/* Size in here reflects original state. */

STRUCT_GETINFO info;

 

struct counter_map *counter_map;

/* Array of hook names */

const char **hooknames;

 

/* Cached position of chain heads (NULL = no cache). */

unsigned int cache_num_chains;

unsigned int cache_num_builtins;

 

 

/* Rule iterator: terminal rule */

STRUCT_ENTRY *cache_rule_end;

 

/* Number in here reflects current state. */

unsigned int new_number;

STRUCT_GET_ENTRIES entries;

};

 

再来看看iptc_init函数,同样在在Libip4tc中,有如下定义:

#define TC_INIT iptc_init

 

在Libiptc.c中,可以看到函数的实现,基本上iptables与内核的交互,都是使用setsockopt函数来实现的,对于获取取规是信息来说,标志位是SO_GET_INFO,而从内核返回回来的规则信息是一个STRUCT_GETINFO结构:

 

TC_HANDLE_T TC_INIT(const char *tablename)

{

TC_HANDLE_T h;

STRUCT_GETINFO info;

unsigned int i;

int tmp;

socklen_t s;

 

iptc_fn = TC_INIT;

 

if (sockfd != -1)

close(sockfd);

 

/*为获取信息打开一个套接字接口*/

sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW);

if (sockfd < 0)

return NULL;

 

s = sizeof(info);

if (strlen(tablename) >= TABLE_MAXNAMELEN) {

errno = EINVAL;

return NULL;

}

strcpy(info.name, tablename);

/*获取规则信息*/

if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0)

return NULL;

 

if ((h = alloc_handle(info.name, info.size, info.num_entries))

== NULL)

return NULL;

 

/* Too hard --RR */

#if 0

sprintf(pathname, "%s/%s", IPT_LIB_DIR, info.name);

dynlib = dlopen(pathname, RTLD_NOW);

if (!dynlib) {

errno = ENOENT;

return NULL;

}

h->hooknames = dlsym(dynlib, "hooknames");

if (!h->hooknames) {

errno = ENOENT;

return NULL;

}

#else

h->hooknames = hooknames;

#endif

 

/* Initialize current state */

h->info = info;

h->new_number = h->info.num_entries;

for (i = 0; i < h->info.num_entries; i++)

h->counter_map[i]

= ((struct counter_map){COUNTER_MAP_NORMAL_MAP, i});

 

h->entries.size = h->info.size;

 

tmp = sizeof(STRUCT_GET_ENTRIES) + h->info.size;

 

if (getsockopt(sockfd, TC_IPPROTO, SO_GET_ENTRIES, &h->entries,

&tmp) < 0) {

free(h);

return NULL;

}

 

CHECK(h);

return h;

}

 

函数为h分配空间,然后赋予相应的值。要理解这个函数,还需要了解STRUCT_GETINFO结构和分配内存空间的函数alloc_handle。

 

#define STRUCT_GETINFO struct ipt_getinfo

 

/* The argument to IPT_SO_GET_INFO */

 

struct ipt_getinfo

{

/* 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;

};

 

/* Allocate handle of given size */

static TC_HANDLE_T

alloc_handle(const char *tablename, unsigned int size, unsigned int num_rules)

{

size_t len;

TC_HANDLE_T h;

 

len = sizeof(STRUCT_TC_HANDLE)

+ size

+ num_rules * sizeof(struct counter_map);

 

if ((h = malloc(len)) == NULL) {

errno = ENOMEM;

return NULL;

}

 

h->changed = 0;

h->cache_num_chains = 0;

h->cache_chain_heads = NULL;

h->counter_map = (void *)h

+ sizeof(STRUCT_TC_HANDLE)

+ size;

strcpy(h->info.name, tablename);

strcpy(h->entries.name, tablename);

 

return h;

}

 

函数list_entries用于显示表下边的链:

/*显示某table下的chain*/

static int

list_entries(const ipt_chainlabel chain, int verbose, int numeric,

int expanded, int linenumbers, iptc_handle_t *handle)

{

int found = 0;

unsigned int format;

const char *this;

 

format = FMT_OPTIONS; /*设置输出格式*/

if (!verbose) /*详细输出模式,,对应-v ,显示匹配的包的数目,包的大小等*/

format |= FMT_NOCOUNTS;

else

format |= FMT_VIA;

 

if (numeric) /*对应-n,以数字的形式输出地址和端口*/

format |= FMT_NUMERIC;

 

if (!expanded) /*对应-x,expand numbers (display exact values)*/

format |= FMT_KILOMEGAGIGA;

 

if (linenumbers) /*输出行的编号*/

format |= FMT_LINENUMBERS;

 

for (this = iptc_first_chain(handle); /*遍历当前table的所有chain*/

this;

this = iptc_next_chain(handle))

{

const struct ipt_entry *i;

unsigned int num;

 

if (chain && strcmp(chain, this) != 0) /*匹配指定chain名,这里用chain &&,即若不指定chain,输出所有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),

num++,

format,

*handle);

i = iptc_next_rule(i, handle); /*移至下一条规则*/

}

found = 1;

}

 

errno = ENOENT;

return found;

}

 

可见,在函数中,由iptc_first_chain和 iptc_next_chain实现了遍历,iptc_first_rule和iptc_next_rule实现了链中规是的遍 历,print_firewall函数在遍历到规则的时候,向终端输出防火墙规则,其第二个参数iptc_get_target又用于获取规则的 target。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值