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 { ...@@ -463,6 +463,8 @@ union mysockaddr {
#endif #endif
}; };
#include "htree.h"
/* bits in flag param to IPv6 callbacks from iface_enumerate() */ /* bits in flag param to IPv6 callbacks from iface_enumerate() */
#define IFACE_TENTATIVE 1 #define IFACE_TENTATIVE 1
#define IFACE_DEPRECATED 2 #define IFACE_DEPRECATED 2
...@@ -486,6 +488,10 @@ union mysockaddr { ...@@ -486,6 +488,10 @@ union mysockaddr {
#define SERV_LOOP 8192 /* server causes forwarding loop */ #define SERV_LOOP 8192 /* server causes forwarding loop */
#define SERV_DO_DNSSEC 16384 /* Validate DNSSEC when using this server */ #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_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 { struct serverfd {
int fd; int fd;
...@@ -954,7 +960,17 @@ extern struct daemon { ...@@ -954,7 +960,17 @@ extern struct daemon {
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces; struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces;
struct bogus_addr *bogus_addr, *ignore_addr; struct bogus_addr *bogus_addr, *ignore_addr;
struct server *servers; struct server *servers;
struct server *pseudo_server;
struct server *priv_servers; /* servers for --server / --address */
/*TODO remove? */
struct ipsets *ipsets; 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 */ int log_fac; /* log facility */
char *log_file; /* optional log file */ char *log_file; /* optional log file */
int max_logs; /* queue limit */ int max_logs; /* queue limit */
......
...@@ -115,12 +115,86 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne ...@@ -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. */ domain.org and sub.domain.org to exist. */
unsigned int namelen = strlen(qdomain); unsigned int namelen = strlen(qdomain);
unsigned int matchlen = 0; //unsigned int matchlen = 0;
struct server *serv; //struct server *serv, *fwdserv = NULL;
struct server *fwdserv = NULL;
unsigned int flags = 0; 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) 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) 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; 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 ...@@ -156,9 +230,6 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne
else else
{ {
unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6; 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 (domainlen != 0 && domainlen == matchlen)
{ {
if ((serv->flags & SERV_LITERAL_ADDRESS)) if ((serv->flags & SERV_LITERAL_ADDRESS))
...@@ -202,6 +273,8 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne ...@@ -202,6 +273,8 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne
} }
} }
*/
if (flags == 0 && !(qtype & F_QUERY) && if (flags == 0 && !(qtype & F_QUERY) &&
option_bool(OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0) option_bool(OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
/* don't forward A or AAAA queries for simple names, except the empty name */ /* don't forward A or AAAA queries for simple names, except the empty name */
...@@ -561,29 +634,21 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server ...@@ -561,29 +634,21 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
char **sets = 0; char **sets = 0;
int munged = 0, is_sign; int munged = 0, is_sign;
size_t plen; size_t plen;
struct htree_node *np;
struct ipsets *obj;
(void)ad_reqd; (void)ad_reqd;
(void)do_bit; (void)do_bit;
(void)bogusanswer; (void)bogusanswer;
#ifdef HAVE_IPSET #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); np = domain_match(daemon->htree_ipsets, daemon->namebuff);
char *matchstart = daemon->namebuff + namelen - domainlen; if (np)
if (namelen >= domainlen && hostname_isequal(matchstart, ipset_pos->domain) &&
(domainlen == 0 || namelen == domainlen || *(matchstart - 1) == '.' ) &&
domainlen >= matchlen)
{ {
matchlen = domainlen; obj = (struct ipsets *) np->ptr;
sets = ipset_pos->sets; sets = obj->sets;
}
} }
} }
#endif #endif
......
/* htree.c Chen Wei <weichen302@gmail.com>
Use cascade of open addressing hash tables to store config options that
involve domain names.
root
|
+---------------------+
com org
| |
+------------------+ +-------------+
yahoo google twitter debian freebsd
| | | |
www mail +---------+ www
cn jp uk us
|
ftp
The lookup steps over domain name hierarchy top-down. All labels are stored
in open addressing hash tables. Sub-level labels that belong to different
parent nodes are stored separately. e.g. yahoo, google, and twitter are in
one hash table, while debian and freebsd are in another.
The hash table size is power of 2, two hash functions are used to compute
hash bucket. For locating a particular label from hash table, two hash
values are compared first, only if they are match, should the more
expensive string comparison be used to confirm the search.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
#define OPEN_ADDRESSING_MAXPROBE 7
#define OPEN_ADDRESSING_DEFAULT_SIZE 4
#define FNV1_32A_INIT ((uint32_t)0x811c9dc5)
#define max(A, B) ((A) > (B) ? (A) : (B))
static char buf[MAXDNAME];
/* prototypes */
//static struct htree_node *htree_find (struct htree_node *node, char *label);
static void htree_add (struct htree_node *node, struct htree_node *sub);
static void htree_upsizing (struct htree_node *np);
static inline void normalize_domain_name (char *dst, char *src, int len);
/* hash function 1 for double hashing
* 32 bit Fowler/Noll/Vo hash */
static inline uint32_t dblhash_1 (char *key)
{
uint32_t hval = FNV1_32A_INIT;
unsigned char *s = (unsigned char *) key;
while (*s)
{
hval ^= (uint32_t) * s++;
hval +=
(hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
}
return hval;
}
/* hash function 2 for double hashing
* modified Shift-Add-XOR hash, return an odd number */
static inline uint32_t dblhash_2 (char *key)
{
uint32_t h = 0;
unsigned char *s = (unsigned char *) key;
while (*s)
h ^= (h << 5) + (h >> 2) + *s++;
return h % 2 ? h : h + 1;
}
/* convert domain to lower cases, remove leading blank, leading and trailing
* dot. End string with \0 */
static inline void normalize_domain_name (char *d, char *s, int len)
{
int i;
/* skip leading dot and blank */
for ( ; *s != '\0' && (*s == '.' || *s == '\t' || *s == ' '); s++)
;
for (i = 0; i < len && *s != '\0'; i++, s++)
{
if (*s >= 'A' && *s <= 'Z')
d[i] = *s + 'a' - 'A';
else
d[i] = *s;
}
/* should not happen since the source string limited to MAXDNAME */
if (i == len)
i--;
for ( ; d[i] == '.'; i--)
;
if (i < (len - 1))
d[++i] = '\0';
else
/* something wrong with the source string(domain name), it exceeds
* MAXDNAME, terminate the dst string with '\0' anyway */
d[i] = '\0';
}
struct htree_node * htree_init_sub (struct htree_node *node)
{
unsigned n;
if (node->sub != NULL)
return node;
node->sub_size = OPEN_ADDRESSING_DEFAULT_SIZE;
node->sub_loadmax = node->sub_size * 4 / 5; /* max loading factor 0.8 */
node->sub = safe_malloc (node->sub_size * sizeof (struct htree_node *));
for (n = 0; n < node->sub_size; n++)
node->sub[n] = NULL;
return node;
}
/* allocate and initialize a new node */
struct htree_node * htree_new_node (char *label, int label_len)
{
struct htree_node *node;
node = safe_malloc (sizeof (struct htree_node));
if (node == NULL)
return NULL;
if (label == NULL || label_len == 0)
{
node->h1 = 0;
node->h2 = 0;
node->label = NULL;
}
else
{
node->label = strdup (label);
node->h1 = dblhash_1 (label);
node->h2 = dblhash_2 (label);
}
node->sub_count = 0;
node->sub_size = 0;
node->sub_loadmax = 0;
node->sub_maxprobe = 0;
node->sub = NULL;
node->ptr = NULL;
return node;
}
/* double the size of hash table attached to a htree_node, it calls with
* htree_add with each other. The table size starts with 2^2, so that the new
* size remains 2^x, the double hash used is chosen to work with 2^n slots */
static void htree_upsizing (struct htree_node *np)
{
struct htree_node **oldnodes;
unsigned i, oldsize;
oldsize = np->sub_size;
oldnodes = np->sub;
np->sub_size = oldsize * 2;
np->sub_loadmax = np->sub_size * 3 / 4;
np->sub_count = 0;
np->sub_maxprobe = 0;
np->sub = safe_malloc (np->sub_size * sizeof (struct htree_node *));
for (i = 0; i < np->sub_size; i++)
np->sub[i] = NULL;
for (i = 0; i < oldsize; i++)
{
if (oldnodes[i] != NULL)
{
htree_add (np, oldnodes[i]);
}
}
free (oldnodes);
}
/* add a sub-node, upsize if needed, calls with htree_upsizing with each other */
static void htree_add (struct htree_node *node, struct htree_node *sub)
{
int n;
uint32_t dh, idx;
if (node->sub == NULL)
htree_init_sub (node);
n = 0;
dh = sub->h1;
while (1)
{
/* eq to dh % node->sub_size, since sub_size is power of 2*/
idx = dh & (node->sub_size - 1);
if (node->sub[idx] == NULL)
{
node->sub[idx] = sub;
node->sub_count += 1;
break;
}
else
{
dh += sub->h2;
n++;
}
}
node->sub_maxprobe = max (n, node->sub_maxprobe);
/*
* If it takes a lots of probes to find an empty slot, or the used slots
* close to loading max, upsize the table
*/
if (node->sub_maxprobe > OPEN_ADDRESSING_MAXPROBE ||
node->sub_count > node->sub_loadmax)
{
htree_upsizing (node);
}
return;
}
struct htree_node *htree_find_or_add (struct htree_node *node, char *label)
{
struct htree_node *np;
if ((np = htree_find (node, label)) == NULL)
{
if (node->sub == NULL)
htree_init_sub (node);
np = htree_new_node (label, strlen (label));
htree_add (node, np);
}
return np;
}
/* lookup the label in node's sub, return the pointer, NULL if not found */
struct htree_node *htree_find (struct htree_node *node, char *label)
{
uint32_t h1, h2, dh, idx;
struct htree_node *np;
/* this domain doesn't have sub-domains */
if (node->sub == NULL)
return NULL;
dh = h1 = dblhash_1 (label);
h2 = dblhash_2 (label);
idx = dh & (node->sub_size - 1);
while ((np = node->sub[idx]) != NULL)
{
if (np->h1 == h1 && np->h2 == h2)
if (strcmp (np->label, label) == 0)
return np;
dh += h2;
idx = dh & (node->sub_size - 1);
}
return NULL;
}
/* look up the whole domain pattern by step over DNS name hierarchy top down.
* for example, if the pattern is cn.debian.org, the lookup will start with
* org, then debian, then cn. The longest pattern wins. */
struct htree_node * domain_match(struct htree_node *root, char *domain)
{
char *labels[MAXLABELS];
int i, label_num;
int len = (int) sizeof(buf);
struct htree_node *node, *res;
if (root == NULL)
return NULL;
memset(buf, 0, sizeof(buf));
normalize_domain_name (buf, domain, len);
for (i = 0; i < MAXLABELS; i++)
labels[i] = NULL;
label_num = 0;
labels[label_num++] = &buf[0];
/* split domain name into labels */
for (i = 0; i < len && buf[i] != '\0'; i++)
{
if (buf[i] == '.')
{
buf[i] = '\0';
labels[label_num++] = &buf[i + 1];
}
}
node = root;
res = NULL;
for (i = label_num - 1; i >= 0; i--)
{
node = htree_find (node, labels[i]);
if (node == NULL)
break;
/* repeatedly overwrite with node that has option set while walk down the
* domain name tree to match config option with longest pattern */
if (node->ptr != NULL)
res = node;
}
return res;
}
/* add a domain pattern in the form of debian.org to root or find the node
* match the domain pattern (for modify) */
struct htree_node *domain_find_or_add (struct htree_node *root, char *domain)
{
char *labels[MAXLABELS];
int i, label_num;
int len = (int) sizeof(buf);
struct htree_node *node;
memset(buf, 0, sizeof(buf));
normalize_domain_name (buf, domain, len);
for (i = 0; i < MAXLABELS; i++)
labels[i] = NULL;
label_num = 0;
labels[label_num++] = &buf[0];
for (i = 0; i < len && buf[i] != '\0'; i++)
{
if (buf[i] == '.')
{
buf[i] = '\0';
labels[label_num++] = &buf[i + 1];
}
}
node = root;
for (i = label_num - 1; i >= 0; i--)
node = htree_find_or_add (node, labels[i]);
return node;
}
/* free node and all sub-nodes recursively. Unused. */
void htree_free (struct htree_node *node)
{
struct htree_node *np;
unsigned i;
if (node->sub_count > 0)
{
for (i = 0; i < node->sub_size; i++)
{
np = node->sub[i];
if (np != NULL)
{
if (np->label != NULL)
free (np->label);
if (np->ptr != NULL)
free (np->ptr);
htree_free (np);
}
}
free (node->sub);
}
free (node);
}
/* only compare addr, source_addr, interface, and flags */
static inline int is_same_server(struct server *s1, struct server *s2)
{
if (memcmp(&s1->addr, &s2->addr, sizeof(union mysockaddr)) != 0)
return 0;
if (strncmp(s1->interface, s2->interface, IF_NAMESIZE + 1) != 0)
return 0;
if (s1->flags != s2->flags)
return 0;
return 1;
}
/* duplicate a struct server, but only copy addr, source_addr, interfaces, and
* flags
* return the allocated pointer */
static inline struct server *serverdup(struct server *src)
{
struct server *dst;
dst = safe_malloc(sizeof(struct server));
memcpy(dst, src, sizeof(struct server));
return dst;
}
/* lookup server by compare addr, source_addr, interface, and flags with
* servers in daemon->priv_servers linked list. If no match found, then insert a new
* server
*
* Return the lookup result or the newly created server */
struct server *lookup_or_install_new_server(struct server *serv)
{
struct server *res;
res = NULL;
for (res = daemon->priv_servers; res != NULL; res = res->next) {
if (is_same_server(res, serv))
break;
}
if (res == NULL) {
res = serverdup(serv);
res->next = daemon->priv_servers;
daemon->priv_servers = res;
}
return res;
}
/* print the daemon->htree_special_domains tree recursively */
void print_server_special_domains (struct htree_node *node, char *parents[],
int current_level, int *count)
{
struct htree_node *np;
struct special_domain *obj;
char ip_buf[ADDRSTRLEN];
int j, level;
int port = 0;
uint32_t i;
level = current_level + 1;
if (node->label != NULL)
{
parents[level] = node->label;
if (node->ptr != NULL)
{
obj = (struct special_domain *) node->ptr;
if (obj->domain_flags & SERV_HAS_DOMAIN)
{
if ((*count)++ < SERVERS_LOGGED)
{
memset (buf, 0, MAXDNAME);
for (j = level; j > 1; j--)
{
strcat (buf, parents[j]);
strcat (buf, ".");
}
buf[strlen (buf) - 1] = '\0';
port = prettyprint_addr (&obj->server->addr, ip_buf);
my_syslog(LOG_INFO, _("using nameserver %s#%d for domain %s"),
ip_buf, port, buf);
}
}
}
}
if (node->sub_count > 0)
{
for (i = 0; i < node->sub_size; i++)
if ((np = node->sub[i]) != NULL)
print_server_special_domains (np, parents, level, count);
}
}
/* 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) ...@@ -1456,7 +1456,7 @@ void check_servers(void)
for (count = 0, serv = daemon->servers; serv; serv = serv->next) 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. */ /* Init edns_pktsz for newly created server records. */
if (serv->edns_pktsz == 0) if (serv->edns_pktsz == 0)
...@@ -1522,7 +1522,8 @@ void check_servers(void) ...@@ -1522,7 +1522,8 @@ void check_servers(void)
serv->sfd->used = 1; 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) if (++count > SERVERS_LOGGED)
continue; continue;
......
...@@ -2336,7 +2336,9 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -2336,7 +2336,9 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case 'A': /* --address */ case 'A': /* --address */
case LOPT_NO_REBIND: /* --rebind-domain-ok */ 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); unhide_metas(arg);
...@@ -2409,6 +2411,66 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -2409,6 +2411,66 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
ret_err(err); ret_err(err);
} }
/*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; serv = newlist;
while (serv->next) while (serv->next)
{ {
...@@ -2420,6 +2482,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -2420,6 +2482,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
} }
serv->next = daemon->servers; serv->next = daemon->servers;
daemon->servers = newlist; daemon->servers = newlist;
}
break; break;
} }
...@@ -2464,7 +2528,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -2464,7 +2528,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
#else #else
{ {
struct ipsets ipsets_head; struct ipsets ipsets_head;
struct ipsets *ipsets = &ipsets_head; struct ipsets *tmp, *ipsets = &ipsets_head;
int size; int size;
char *end; char *end;
char **sets, **sets_pos; char **sets, **sets_pos;
...@@ -2518,9 +2582,90 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -2518,9 +2582,90 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
*sets_pos = 0; *sets_pos = 0;
for (ipsets = &ipsets_head; ipsets->next; ipsets = ipsets->next) for (ipsets = &ipsets_head; ipsets->next; ipsets = ipsets->next)
ipsets->next->sets = sets; ipsets->next->sets = sets;
ipsets->next = daemon->ipsets; //ipsets->next = daemon->ipsets;
daemon->ipsets = ipsets_head.next; 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; break;
} }
#endif #endif
...@@ -4541,6 +4686,18 @@ void read_opts(int argc, char **argv, char *compile_opts) ...@@ -4541,6 +4686,18 @@ void read_opts(int argc, char **argv, char *compile_opts)
daemon->soa_expiry = SOA_EXPIRY; daemon->soa_expiry = SOA_EXPIRY;
daemon->max_port = MAX_PORT; 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 #ifndef NO_ID
add_txt("version.bind", "dnsmasq-" VERSION, 0 ); add_txt("version.bind", "dnsmasq-" VERSION, 0 );
add_txt("authors.bind", "Simon Kelley", 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