Commit c4b60be5 authored by Chen Wei's avatar Chen Wei

port fastlookup to 2.77test4

The basic idea is use a placeholder in daemon->servers, whenever it need to
match --server/--address, instead of iterate through the linked list, dnsmasq
will look it up on daemon->htree_special_domains, then copy the match result
to the placeholder.

Ipsets match is simpler, the match result can be used directly.

The code is re-organized to use upstream functions/blocks when possible, and
most newly added code blocks are separated from current upstream source.
Hopefully, it will be easier for others to review.
parent 62f9c0d4
......@@ -463,6 +463,8 @@ union mysockaddr {
#endif
};
#include "htree.h"
/* bits in flag param to IPv6 callbacks from iface_enumerate() */
#define IFACE_TENTATIVE 1
#define IFACE_DEPRECATED 2
......@@ -486,6 +488,10 @@ union mysockaddr {
#define SERV_LOOP 8192 /* server causes forwarding loop */
#define SERV_DO_DNSSEC 16384 /* Validate DNSSEC when using this server */
#define SERV_GOT_TCP 32768 /* Got some data from the TCP connection */
#define SERV_PSEUDO 65536 /* The psudo-server in daemon->server linked
list, whenever a match found by lookup htree, the server address/domain/
flags is copied to this server, then the usual daemon->server-next iter
will match it by compare domain. */
struct serverfd {
int fd;
......@@ -954,7 +960,17 @@ extern struct daemon {
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces;
struct bogus_addr *bogus_addr, *ignore_addr;
struct server *servers;
struct server *pseudo_server;
struct server *priv_servers; /* servers for --server / --address */
/*TODO remove? */
struct ipsets *ipsets;
struct htree_node *htree_ipsets; /* for --ipset domain names*/
/* setnames stored here to reduce redundancy */
struct htree_node *htree_ipset_names;
/* for --server/local/address/rebind-domain-ok domain names */
struct htree_node *htree_special_domains;
int log_fac; /* log facility */
char *log_file; /* optional log file */
int max_logs; /* queue limit */
......
......@@ -115,12 +115,86 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne
domain.org and sub.domain.org to exist. */
unsigned int namelen = strlen(qdomain);
unsigned int matchlen = 0;
struct server *serv;
//unsigned int matchlen = 0;
//struct server *serv, *fwdserv = NULL;
struct server *fwdserv = NULL;
unsigned int flags = 0;
unsigned int sflag;
struct htree_node *np;
struct special_domain *obj;
/* label of root node is "#", means --address=/#/1.2.3.4 */
if (daemon->htree_special_domains && daemon->htree_special_domains->label &&
*daemon->htree_special_domains->label == '#')
np = daemon->htree_special_domains;
else
np = domain_match (daemon->htree_special_domains, qdomain);
if (np)
{
obj = (struct special_domain *) np->ptr;
*type = obj->domain_flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_DO_DNSSEC);
if (obj->domain_flags & SERV_NO_REBIND)
*norebind = 1;
/* no server, domain is local only */
if (obj->domain_flags & SERV_NO_ADDR)
{
flags = F_NXDOMAIN;
}
else if (obj->domain_flags & SERV_LITERAL_ADDRESS)
{
/* --address and AF matches */
sflag = obj->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
if (sflag & qtype)
{
flags = sflag;
if (obj->addr.sa.sa_family == AF_INET)
*addrpp = (struct all_addr *) &obj->addr.in.sin_addr;
#ifdef HAVE_IPV6
else
*addrpp = (struct all_addr *) &obj->addr.in6.sin6_addr;
#endif
}
else if (!flags || (flags & F_NXDOMAIN))
flags = F_NOERR;
}
else if (obj->domain_flags & SERV_USE_RESOLV)
{
/* --server=8.8.8.8 */
*type = 0; /* use normal server */
fwdserv = NULL;
}
else
{
fwdserv = obj->server;
flags = 0;
}
}
else
{
*type = 0; /* use normal servers for this domain */
fwdserv = NULL;
}
if (fwdserv)
{
daemon->pseudo_server->domain = qdomain;
memcpy (&daemon->pseudo_server->addr, &fwdserv->addr, sizeof (union mysockaddr));
daemon->pseudo_server->flags = obj->domain_flags;
*domain = qdomain;
printf(" debug: in search_servers found server for %s\n", qdomain);
}
else
{
daemon->pseudo_server->domain = NULL;
}
/*
for (serv = daemon->servers; serv; serv=serv->next)
/* domain matches take priority over NODOTS matches */
if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0)
{
unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
......@@ -156,9 +230,6 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne
else
{
unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
/* implement priority rules for --address and --server for same domain.
--address wins if the address is for the correct AF
--server wins otherwise. */
if (domainlen != 0 && domainlen == matchlen)
{
if ((serv->flags & SERV_LITERAL_ADDRESS))
......@@ -202,6 +273,8 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne
}
}
*/
if (flags == 0 && !(qtype & F_QUERY) &&
option_bool(OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
/* don't forward A or AAAA queries for simple names, except the empty name */
......@@ -561,30 +634,22 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
char **sets = 0;
int munged = 0, is_sign;
size_t plen;
struct htree_node *np;
struct ipsets *obj;
(void)ad_reqd;
(void)do_bit;
(void)bogusanswer;
#ifdef HAVE_IPSET
if (daemon->ipsets && extract_request(header, n, daemon->namebuff, NULL))
if (daemon->htree_ipsets && extract_request(header, n, daemon->namebuff, NULL))
{
/* Similar algorithm to search_servers. */
struct ipsets *ipset_pos;
unsigned int namelen = strlen(daemon->namebuff);
unsigned int matchlen = 0;
for (ipset_pos = daemon->ipsets; ipset_pos; ipset_pos = ipset_pos->next)
{
unsigned int domainlen = strlen(ipset_pos->domain);
char *matchstart = daemon->namebuff + namelen - domainlen;
if (namelen >= domainlen && hostname_isequal(matchstart, ipset_pos->domain) &&
(domainlen == 0 || namelen == domainlen || *(matchstart - 1) == '.' ) &&
domainlen >= matchlen)
{
matchlen = domainlen;
sets = ipset_pos->sets;
}
}
np = domain_match(daemon->htree_ipsets, daemon->namebuff);
if (np)
{
obj = (struct ipsets *) np->ptr;
sets = obj->sets;
}
}
#endif
......
This diff is collapsed.
/* htree.h */
struct htree_node {
char *label; /* key */
void *ptr;
/* open addressing hash table uses double hashing */
uint32_t h1; /* from hash function 1 */
uint32_t h2; /* from hash function 2 */
struct htree_node **sub; /* the hash table */
unsigned sub_size; /* size of hash table */
int sub_count; /* items stored in hash table */
int sub_loadmax; /* max items stored before upsizing sub */
int sub_maxprobe; /* max probes for insertion, upsizing upon reach */
};
struct special_domain {
struct server *server;
union mysockaddr addr;
int domain_flags;
};
struct ipsets_names {
char **sets; /* ipsets names end with NULL ptr */
int count;
};
/* htree.c */
#define MAXLABELS 128
struct htree_node *htree_new_node(char *label, int len);
struct htree_node *htree_find (struct htree_node *node, char *label);
struct htree_node *htree_find_or_add(struct htree_node *node, char *label);
struct htree_node *domain_match(struct htree_node *root, char *domain);
struct htree_node *domain_find_or_add(struct htree_node *root, char *domain);
struct server *lookup_or_install_new_server(struct server *serv);
void htree_free (struct htree_node *node);
void print_server_special_domains(struct htree_node *node, char *parents[],
int current_level, int *count);
......@@ -1456,7 +1456,7 @@ void check_servers(void)
for (count = 0, serv = daemon->servers; serv; serv = serv->next)
{
if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)))
if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_PSEUDO)))
{
/* Init edns_pktsz for newly created server records. */
if (serv->edns_pktsz == 0)
......@@ -1522,7 +1522,8 @@ void check_servers(void)
serv->sfd->used = 1;
}
if (!(serv->flags & SERV_NO_REBIND) && !(serv->flags & SERV_LITERAL_ADDRESS))
if (!(serv->flags & SERV_NO_REBIND) && !(serv->flags & SERV_LITERAL_ADDRESS)
&& !(serv->flags & SERV_PSEUDO))
{
if (++count > SERVERS_LOGGED)
continue;
......
......@@ -2336,8 +2336,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case 'A': /* --address */
case LOPT_NO_REBIND: /* --rebind-domain-ok */
{
struct server *serv, *newlist = NULL;
struct server *serv, *tmp,*serv_del, *newlist = NULL;
struct htree_node *np = NULL;
struct special_domain *obj;
unhide_metas(arg);
if (arg && (*arg == '/' || option == LOPT_NO_REBIND))
......@@ -2409,17 +2411,79 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
ret_err(err);
}
serv = newlist;
while (serv->next)
{
serv->next->flags = serv->flags;
serv->next->addr = serv->addr;
serv->next->source_addr = serv->source_addr;
strcpy(serv->next->interface, serv->interface);
serv = serv->next;
}
serv->next = daemon->servers;
daemon->servers = newlist;
/*TODO install htree node and free pointer */
if (daemon->htree_special_domains == NULL)
daemon->htree_special_domains = htree_new_node (NULL, 0);
if (newlist->flags
& (SERV_USE_RESOLV | SERV_LITERAL_ADDRESS
| SERV_NO_ADDR | SERV_HAS_DOMAIN))
{
if (newlist->flags & SERV_USE_RESOLV)
{
np = daemon->htree_special_domains;
free(np->label);
np->label = strdup("#");
}
else
{
np = domain_find_or_add(daemon->htree_special_domains,
newlist->domain);
}
if (np->ptr)
{
obj = (struct special_domain *) np->ptr;
}
else
{
obj = opt_malloc (sizeof (struct special_domain));
memset (obj, 0, sizeof (struct special_domain));
}
obj->domain_flags = newlist->flags;
if (newlist->flags & SERV_NO_ADDR) /* no server */
{
obj->server = NULL;
}
else if (newlist->flags & SERV_LITERAL_ADDRESS)
{
obj->server = NULL;
memcpy (&obj->addr, &newlist->addr, sizeof (union mysockaddr));
}
else if (newlist->flags & SERV_HAS_DOMAIN)
{
/* install the new server into daemon->servers linked list */
obj->server = lookup_or_install_new_server (newlist);
obj->server->domain = NULL;
}
np->ptr = (void *) obj;
/*TODO free linked list */
for (serv_del = newlist; serv_del; ) {
tmp = serv_del->next;
if (serv_del->domain)
free(serv_del->domain);
free(serv_del);
serv_del = tmp;
}
}
else
{
serv = newlist;
while (serv->next)
{
serv->next->flags = serv->flags;
serv->next->addr = serv->addr;
serv->next->source_addr = serv->source_addr;
strcpy(serv->next->interface, serv->interface);
serv = serv->next;
}
serv->next = daemon->servers;
daemon->servers = newlist;
}
break;
}
......@@ -2464,7 +2528,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
#else
{
struct ipsets ipsets_head;
struct ipsets *ipsets = &ipsets_head;
struct ipsets *tmp, *ipsets = &ipsets_head;
int size;
char *end;
char **sets, **sets_pos;
......@@ -2518,9 +2582,90 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
*sets_pos = 0;
for (ipsets = &ipsets_head; ipsets->next; ipsets = ipsets->next)
ipsets->next->sets = sets;
ipsets->next = daemon->ipsets;
//ipsets->next = daemon->ipsets;
daemon->ipsets = ipsets_head.next;
/* TODO */
struct htree_node *np = NULL;
struct htree_node *setname = NULL;
//struct ipsets_names *obj;
struct ipsets *obj;
char **ipsets_cur, **newsets, **newsets_cur;
int i, newsets_size;
if (!daemon->htree_ipsets)
daemon->htree_ipsets = htree_new_node (NULL, 0);
if (!daemon->htree_ipset_names)
daemon->htree_ipset_names = htree_new_node (NULL, 0);
/* store ipsets into htree */
for (ipsets = daemon->ipsets; ipsets; ipsets = ipsets->next)
{
np = domain_find_or_add (daemon->htree_ipsets, ipsets->domain);
i = 0;
if (np->ptr)
{
obj = (struct ipsets *) np->ptr;
for (ipsets_cur = obj->sets; *ipsets_cur; ipsets_cur++)
if (!htree_find(daemon->htree_ipset_names, *ipsets_cur))
i++;
}
else
{
obj = opt_malloc(sizeof(struct ipsets));
memset(obj, 0, sizeof(struct ipsets));
}
newsets_size = size + i;
newsets = newsets_cur = opt_malloc(sizeof(char *) * newsets_size);
if (obj->sets)
{
for (ipsets_cur = obj->sets; *ipsets_cur; ) {
*newsets_cur++ = *ipsets_cur++;
}
}
for (ipsets_cur = ipsets->sets; *ipsets_cur; ipsets_cur++)
{
setname = htree_find_or_add(daemon->htree_ipset_names, *ipsets_cur);
*newsets_cur++ = setname->label;
}
/*
if (np->ptr) {
old_obj = (struct ipsets *) np->ptr;
free(old_obj->sets);
free(old_obj);
}
*/
if (obj->sets)
free(obj->sets);
obj->sets = newsets;
np->ptr = (void *) obj;
}
if (daemon->ipsets->sets)
{
for (ipsets_cur = daemon->ipsets->sets; *ipsets_cur; ipsets_cur++)
free(*ipsets_cur);
free(daemon->ipsets->sets);
}
for (ipsets = daemon->ipsets; ipsets; )
{
tmp = ipsets->next;
if (ipsets->domain)
free(ipsets->domain);
free(ipsets);
ipsets = tmp;
}
break;
}
#endif
......@@ -4541,6 +4686,18 @@ void read_opts(int argc, char **argv, char *compile_opts)
daemon->soa_expiry = SOA_EXPIRY;
daemon->max_port = MAX_PORT;
/* add the psudo-server for htree lookup result */
daemon->pseudo_server = opt_malloc(sizeof(struct server));
memset(daemon->pseudo_server, 0, sizeof(struct server));
daemon->pseudo_server->flags = SERV_PSEUDO;
daemon->pseudo_server->next = daemon->servers;
daemon->servers = daemon->pseudo_server;
daemon->last_server = daemon->servers;
//daemon->servers = opt_malloc(sizeof(struct server));
//memset(daemon->servers, 0, sizeof(struct server));
//daemon->servers->flags = SERV_PSEUDO;
daemon->priv_servers = NULL;
#ifndef NO_ID
add_txt("version.bind", "dnsmasq-" VERSION, 0 );
add_txt("authors.bind", "Simon Kelley", 0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment