Chinaunix首页 | 论坛 | 博客
  • 博客访问: 125782
  • 博文数量: 42
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 354
  • 用 户 组: 普通用户
  • 注册时间: 2014-07-01 15:34
个人简介

不晓得说啥子

文章分类

全部博文(42)

文章存档

2015年(41)

2014年(1)

我的朋友

分类: LINUX

2014-11-02 11:12:30

最近在做路由器行为管理方面的研究,有一个功能要设域名的黑白名单,想也没有想,就用了下面的命令:*******-d   x.x.x.x   -j   *****,我想很多新人都会这样做。整个框架用shell搭建起来了,测试发现这样做根本不行。好!问题来了,为什么这样做不行?当使用 -d 选项加域名iptabels是怎么去解析这条命令的?我猜最终是调用类如 gethostbyname()这样的函数解析到域名的IP,保存规则也是保存的具体IP ,而不是域名,也不会去动态的解析。怎么去证明呢?看源代码:

    首先看iptables-standalone.c,这是iptables的主函数。在进行了一些必要的初始化之后,主函数调用了这个函数ret = do_command4(argc, argv, &table, &handle, false),函数do_command4用来解析用户的参数,在iptables.c中。

在函数int do_command4(这个函数用来解析iptables 命令行参数并将这个规则插入到内核空间)有这样一个片段:

case 's':

set_option(&cs.options, OPT_SOURCE, &cs.fw.ip.invflags, cs.invert);

shostnetworkmask = optarg;

break;

case 'd':

set_option(&cs.options, OPT_DESTINATION, &cs.fw.ip.invflags, cs.invert);

dhostnetworkmask = optarg;

break;

    这两个case获取用户输入的-s 和 -d 选项的参数,并设置cs.optioncommand_state结构),这里就具体讲一下-d选项吧。在do_command4()函数后部分有这样一段代码:

if (shostnetworkmask)

xtables_ipparse_multiple(shostnetworkmask, &saddrs,&smasks, &nsaddrs);

if (dhostnetworkmask)

xtables_ipparse_multiple(dhostnetworkmask, &daddrs, &dmasks, &ndaddrs);

这里的dhostetworkmask(如果不为空)是在case ‘d’中得到的参数,如果不为空,这里调用Xtables_ipparse_multiple()来将IP地址和掩码解析到in_addr的结构中。下面来看看这个解析IP地址和掩码的函数,具体定义在xtables.c中。

void xtables_ipparse_multiple(const char *name, struct in_addr **addrpp,

                              struct in_addr **maskpp, unsigned int *naddrs)

{

struct in_addr *addrp;

char buf[256], *p, *next;

unsigned int len, i, j, n, count = 1;

const char *loop = name;

 

/*这个while循环得到参数中有几个IP地址或者是域名,这才知道—选项后面的IP和域名是可以输入很多,分别用逗号隔开就ok*/

while ((loop = strchr(loop, ',')) != NULL) {

++count;

++loop; /* skip ',' */

}

 

 

/*根据得到的参数个数为两个存储IP地址和MASK 的结构分配相应的内存*/

*addrpp = xables_malloc(sizeof(struct in_addr) * count);

*maskpp = xtables_malloc(sizeof(struct in_addr) * count);

 

loop = name;

/*for循环开始解析各个参数了*/

for (i = 0; i < count; ++i) {

while (isspace(*loop))

++loop;

next = strchr(loop, ',');

if (next != NULL)

len = next - loop;

else

len = strlen(loop);

if (len > sizeof(buf) - 1)

xt_params->exit_err(PARAMETER_PROBLEM,

"Hostname too long");

strncpy(buf, loop, len);

buf[len] = '\0';

/*解析掩码*/

if ((p = strrchr(buf, '/')) != NULL) {

*p = '\0';

addrp = parse_ipmask(p + 1);

} else {

addrp = parse_ipmask(NULL);

}

memcpy(*maskpp + i, addrp, sizeof(*addrp));

 

/* if a null mask is given, the name is ignored, like in "any/0" */

if ((*maskpp + i)->s_addr == 0)

/*

 * A bit pointless to process multiple addresses

 * in this case...

 */

strcpy(buf, "0.0.0.0");

/*重点在这里,解析IP地址*/

addrp = ipparse_hostnetwork(buf, &n);

if (n > 1) {

count += n - 1;

*addrpp = xtables_realloc(*addrpp,

          sizeof(struct in_addr) * count);

*maskpp = xtables_realloc(*maskpp,

          sizeof(struct in_addr) * count);

for (j = 0; j < n; ++j)

/* for each new addr */

memcpy(*addrpp + i + j, addrp + j,

       sizeof(*addrp));

for (j = 1; j < n; ++j)

/* for each new mask */

memcpy(*maskpp + i + j, *maskpp + i,

       sizeof(*addrp));

i += n - 1;

} else {

memcpy(*addrpp + i, addrp, sizeof(*addrp));

}

/* free what ipparse_hostnetwork had allocated: */

free(addrp);

if (next == NULL)

break;

loop = next + 1;

}

*naddrs = count;

for (i = 0; i < count; ++i)

(*addrpp+i)->s_addr &= (*maskpp+i)->s_addr;

}

ipparse_hostnetwork()函数具体定义如下:

static struct in_addr *

ipparse_hostnetwork(const char *name, unsigned int *naddrs)

{

struct in_addr *addrptmp, *addrp;

 

if ((addrptmp = xtables_numeric_to_ipaddr(name)) != NULL ||

    (addrptmp = network_to_ipaddr(name)) != NULL) {

addrp = xtables_malloc(sizeof(struct in_addr));

memcpy(addrp, addrptmp, sizeof(*addrp));

*naddrs = 1;

return addrp;

}

if ((addrptmp = host_to_ipaddr(name, naddrs)) != NULL)

return addrptmp;

 

xt_params->exit_err(PARAMETER_PROBLEM, "host/network `%s' not found", name);

}

这个函数中前部分先尝试直接将参数用两种方式解析成IP地址(不是域名的形式时),如果可以直接解析,则直接返回,naddrs记录解析到的IP个数。如果前两种方式不能解析,则调用函数host_to_ipaddr()用域名的方式解析。Host_to_ipaddr()函数具体定义如下:

 

 

static struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr)

{

struct hostent *host;

struct in_addr *addr;

unsigned int i;

 

*naddr = 0;

if ((host = gethostbyname(name)) != NULL) {

if (host->h_addrtype != AF_INET ||

    host->h_length != sizeof(struct in_addr))

return NULL;

 

while (host->h_addr_list[*naddr] != NULL)

++*naddr;

addr = xtables_calloc(*naddr, sizeof(struct in_addr));

for (i = 0; i < *naddr; i++)

memcpy(&addr[i], host->h_addr_list[i],

       sizeof(struct in_addr));

return addr;

}

return NULL;

}

Host_to_addr()最终调用的是gethostbyname()函数来尝试用域名的方式解析这个参数,如果解析成功则将解析到的IP地址组和IP个数返回,如果不能解析则返回NULL。正如我之前猜的那样,-d选项确实是调用了gethostbyname()函数,得到的IP也只是它能解析出来的几个,所以这印证了我前面那个框架的错误。问题来了,只用iptables怎么样才能禁止或允许一个域名呢?

 

PS:第一次在CU发博客,iptables也是刚接触不久,只是记录一下自己的学习过程,如果哪里写错了还望大家多包涵。

接下来一篇文章会分析整个iptables的框架。

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

上一篇:没有了

下一篇:拓扑排序

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