近期在android10的项目中用到了dnsmasq,正如大家所了解的一样,这东西是个解析并缓存dns的工具。但是本人发现无论预装的2.51版本还是我后来移植源码编译的2.78版本都不能正常。我本是打算用dnsmasq的 conf-file配置调用ipset的,但是通过log发现,即使dnsmasq成功的解析了ipset的指令,但是并没有设置成功。
configfile.con
ipset=/baidu.com.com/iplist
dnsmasq/src/option.c // 此程序是专门解析各种配置指令的
case LOPT_IPSET: /* --ipset */
#ifndef HAVE_IPSET
ret_err(_("recompile with HAVE_IPSET defined to enable ipset directives"));
break;
#else
{
struct ipsets ipsets_head;
struct ipsets *ipsets = &ipsets_head;
int size;
char *end;
char **sets, **sets_pos;
memset(ipsets, 0, sizeof(struct ipsets));
unhide_metas(arg);
if (arg && *arg == '/')
{
arg++;
while ((end = split_chr(arg, '/')))
{
char *domain = NULL;
/* elide leading dots - they are implied in the search algorithm */
while (*arg == '.')
arg++;
/* # matches everything and becomes a zero length domain string */
if (strcmp(arg, "#") == 0 || !*arg)
domain = "";
else if (strlen(arg) != 0 && !(domain = canonicalise_opt(arg)))
ret_err(gen_err);
ipsets->next = opt_malloc(sizeof(struct ipsets));
ipsets = ipsets->next;
memset(ipsets, 0, sizeof(struct ipsets));
ipsets->domain = domain;
arg = end;
my_syslog(LOG_INFO, _("junqiang, domain:%s arg: %s"), domain, arg);
}
}
else
{
ipsets->next = opt_malloc(sizeof(struct ipsets));
ipsets = ipsets->next;
memset(ipsets, 0, sizeof(struct ipsets));
ipsets->domain = "";
}
if (!arg || !*arg)
ret_err(gen_err);
for (size = 2, end = arg; *end; ++end)
if (*end == ',')
++size;
sets = sets_pos = opt_malloc(sizeof(char *) * size);
do {
end = split(arg);
*sets_pos++ = opt_string_alloc(arg);
arg = end;
} while (end);
*sets_pos = 0;
for (ipsets = &ipsets_head; ipsets->next; ipsets = ipsets->next)
ipsets->next->sets = sets;
ipsets->next = daemon->ipsets;
daemon->ipsets = ipsets_head.next;
break;
}
#endif
I/dnsmasq: started, version 2.78 cachesize 150
I/dnsmasq: compile time options: no-IPv6 GNU-getopt no-DBus no-i18n no-IDN DHCP no-DHCPv6 no-scripts no-TFTP no-conntrack ipset auth no-DNSSEC loop-detect inotify
I/dnsmasq: reading /data/system/dnsmasq/resolv.dnsmasq.conf
I/dnsmasq: using nameserver 223.5.5.5#53
E/dnsmasq: bad address at /etc/hosts line 2
I/dnsmasq: read /etc/hosts - 1 addresses
I/dnsmasq: junqiang, domain:baidu.com arg: iplist
从log来看 解析完指令后,dnsmasq的工作就没有再继续了。。。 肯定是中间哪里出问题导致程序没有继续运行下去。
然后就在dnsmasq.c中开始打log,发现在check_dns_listeners(time_t now)之后就没有其他进一步操作了
static void check_dns_listeners(time_t now)
{
struct serverfd *serverfdp;
struct listener *listener;
int i;
int pipefd[2];
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
if (poll_check(serverfdp->fd, POLLIN))
reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
if (daemon->port != 0 && !daemon->osport)
for (i = 0; i < RANDOM_SOCKS; i++)
if (daemon->randomsocks[i].refcount != 0 &&
poll_check(daemon->randomsocks[i].fd, POLLIN))
reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
/* Races. The child process can die before we read all of the data from the
pipe, or vice versa. Therefore send tcp_pids to zero when we wait() the
process, and tcp_pipes to -1 and close the FD when we read the last
of the data - indicated by cache_recv_insert returning zero.
The order of these events is indeterminate, and both are needed
to free the process slot. Once the child process has gone, poll()
returns POLLHUP, not POLLIN, so have to check for both here. */
if (!option_bool(OPT_DEBUG))
for (i = 0; i < MAX_PROCS; i++)
if (daemon->tcp_pipes[i] != -1 &&
poll_check(daemon->tcp_pipes[i], POLLIN | POLLHUP) &&
!cache_recv_insert(now, daemon->tcp_pipes[i]))
{
close(daemon->tcp_pipes[i]);
daemon->tcp_pipes[i] = -1;
}
for (listener = daemon->listeners; listener; listener = listener->next)
{
if (listener->fd != -1 && poll_check(listener->fd, POLLIN))
receive_query(listener, now);
#ifdef HAVE_TFTP
if (listener->tftpfd != -1 && poll_check(listener->tftpfd, POLLIN))
tftp_request(listener, now);
#endif
...
从上面代码中我们可以看到在reply_query操作之前都会进行poll_check。 从阅读代码我们发现运行ipset指令的过程就在reply_query中进行的。那么思路就很清晰了,看看poll_check为什么会不成功。
poll.c
int do_poll(int timeout)
{
return poll(pollfds, nfds, timeout);
}
int poll_check(int fd, short event)
{
nfds_t i = fd_search(fd);
if (i < nfds && pollfds[i].fd == fd)
return pollfds[i].revents & event;
return 0;
}
从上面这段代码中我们又可以知道poll_check是进行了事件检查,检查do_poll是否有相应时间的发生。 那么poll又是在获取什么呢???
继续阅读代码发现:
在dnsmasq.c刚开始初始化中 先调用了create