Commit 0deebaea authored by Chen Wei's avatar Chen Wei

change namespace from dict_ to htree_

parent f4ef873e
...@@ -24,7 +24,7 @@ MANDIR = $(PREFIX)/share/man ...@@ -24,7 +24,7 @@ MANDIR = $(PREFIX)/share/man
LOCALEDIR = $(PREFIX)/share/locale LOCALEDIR = $(PREFIX)/share/locale
BUILDDIR = $(SRC) BUILDDIR = $(SRC)
DESTDIR = DESTDIR =
CFLAGS = -Wall -W -O2 -g CFLAGS = -Wall -W -O0 -g
LDFLAGS = LDFLAGS =
COPTS = COPTS =
RPM_OPT_FLAGS = RPM_OPT_FLAGS =
...@@ -73,7 +73,7 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \ ...@@ -73,7 +73,7 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \ dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \ helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \ dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
domain.o dnssec.o blockdata.o tables.o loop.o inotify.o dict.o domain.o dnssec.o blockdata.o tables.o loop.o inotify.o htree.o
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \ hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
dns-protocol.h radv-protocol.h ip6addr.h dns-protocol.h radv-protocol.h ip6addr.h
......
...@@ -250,7 +250,7 @@ int main (int argc, char **argv) ...@@ -250,7 +250,7 @@ int main (int argc, char **argv)
#endif #endif
#ifdef HAVE_IPSET #ifdef HAVE_IPSET
if (daemon->dh_ipsets) if (daemon->htree_ipsets)
ipset_init(); ipset_init();
#endif #endif
......
...@@ -510,28 +510,20 @@ struct server { ...@@ -510,28 +510,20 @@ struct server {
struct server *next; struct server *next;
}; };
struct ipsets { struct htree_node {
char **sets; char *label; /* key */
char *domain; void *ptr;
struct ipsets *next; uint32_t h1; /* from hash function 1 */
}; /*
* hash value from hash function 2, used for double hashing in open
/* a dictionary node for open addressing hash table * addressing hash table
* it has a key, "label", and a value "obj" as container, there are several */
* other values for maintaining the hash table and lookup uint32_t h2;
* struct htree_node **sub; /* the hash table */
* For ipsets match, only INSERT and LOOKUP operation needed unsigned sub_size; /* size of hash table */
*/ int sub_count; /* items stored in hash table */
struct dict_node { int sub_loadmax; /* max items stored before upsizing sub */
char *label; /* key */ int sub_maxprobe; /* max probes for insertion, upsizing upon reach */
void *obj; /* the value, can point to anything */
uint32_t h1; /* from hash function 1 */
uint32_t h2; /* from hash function 2 */
unsigned sub_slots; /* size of hash table sub */
int sub_count; /* items stored in sub */
int sub_loadmax; /* max items stored before upsize sub */
int sub_maxjump; /* max jumps for insertion, upsize when reach */
struct dict_node **sub;
}; };
struct special_domain { struct special_domain {
...@@ -540,7 +532,6 @@ struct special_domain { ...@@ -540,7 +532,6 @@ struct special_domain {
int domain_flags; int domain_flags;
}; };
struct ipsets_names { struct ipsets_names {
char **sets; /* ipsets names end with NULL ptr */ char **sets; /* ipsets names end with NULL ptr */
int count; int count;
...@@ -974,11 +965,12 @@ extern struct daemon { ...@@ -974,11 +965,12 @@ 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 ipsets *ipsets;
struct dict_node *dh_ipsets; struct htree_node *htree_ipsets; /* for --ipset domain names*/
struct dict_node *dh_ipset_names; /* setnames stored here to reduce redundancy */
struct dict_node *dh_special_domains; 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 */
...@@ -1405,16 +1397,15 @@ void ipset_init(void); ...@@ -1405,16 +1397,15 @@ void ipset_init(void);
int add_to_ipset(const char *setname, const struct all_addr *ipaddr, int flags, int remove); int add_to_ipset(const char *setname, const struct all_addr *ipaddr, int flags, int remove);
#endif #endif
/* dict.c */ /* htree.c */
#define MAXLABELS 128 #define MAXLABELS 128
struct dict_node *new_dictnode (char *label, int len); struct htree_node *htree_new_node(char *label, int len);
struct dict_node *add_or_lookup_dictnode (struct dict_node *node, char *label); struct htree_node *htree_find_or_add(struct htree_node *node, char *label);
struct dict_node *lookup_domain(struct dict_node *root, char *domain); struct htree_node *domain_match(struct htree_node *root, char *domain);
struct dict_node *match_domain(struct dict_node *root, char *domain); struct htree_node *domain_find_or_add(struct htree_node *root, char *domain);
struct dict_node *add_or_lookup_domain (struct dict_node *root, char *domain);
struct server *lookup_or_install_new_server(struct server *serv); struct server *lookup_or_install_new_server(struct server *serv);
void free_dicttree (struct dict_node *node); void htree_free (struct htree_node *node);
void print_server_special_domains(struct dict_node *node, void print_server_special_domains(struct htree_node *node,
char *parents[], int current_level); char *parents[], int current_level);
/* helper.c */ /* helper.c */
......
...@@ -130,9 +130,9 @@ int send_from(int fd, int nowild, char *packet, size_t len, ...@@ -130,9 +130,9 @@ int send_from(int fd, int nowild, char *packet, size_t len,
stored in fwdserv, unless --server=/example.org/#, in which case fwdserv stored in fwdserv, unless --server=/example.org/#, in which case fwdserv
will be NULL, means use normal server will be NULL, means use normal server
if matches --rebind-domain-ok, the pass in norebind will be set to 1 if matches --rebind-domain-ok, the passed in norebind will be set to 1
we find largest match, e.g. given pattern debian.org and cn.debian.org, we find longest match, e.g. given pattern debian.org and cn.debian.org,
ftp.cn.debian.org will match cn.debian.org ftp.cn.debian.org will match cn.debian.org
*/ */
static unsigned int static unsigned int
...@@ -143,27 +143,27 @@ search_servers (time_t now, struct all_addr **addrpp, ...@@ -143,27 +143,27 @@ search_servers (time_t now, struct all_addr **addrpp,
unsigned int namelen = strlen (qdomain); unsigned int namelen = strlen (qdomain);
unsigned int flags = 0; unsigned int flags = 0;
unsigned int sflag; unsigned int sflag;
struct dict_node *np; struct htree_node *np;
struct special_domain *obj; struct special_domain *obj;
*type = 0; *type = 0;
/* label of root node is "#", means --address=/#/1.2.3.4 */ /* label of root node is "#", means --address=/#/1.2.3.4 */
if (daemon->dh_special_domains && daemon->dh_special_domains->label && if (daemon->htree_special_domains && daemon->htree_special_domains->label &&
*daemon->dh_special_domains->label == '#') *daemon->htree_special_domains->label == '#')
np = daemon->dh_special_domains; np = daemon->htree_special_domains;
else else
np = match_domain (daemon->dh_special_domains, qdomain); np = domain_match (daemon->htree_special_domains, qdomain);
if (np != NULL) if (np != NULL)
{ {
obj = (struct special_domain *) np->obj; obj = (struct special_domain *) np->ptr;
*type |= SERV_HAS_DOMAIN; *type |= SERV_HAS_DOMAIN;
if (obj->domain_flags & SERV_NO_REBIND) if (obj->domain_flags & SERV_NO_REBIND)
*norebind = 1; *norebind = 1;
// no server, domain is local only /* no server, domain is local only */
if (obj->domain_flags & SERV_NO_ADDR) if (obj->domain_flags & SERV_NO_ADDR)
{ {
flags = F_NXDOMAIN; flags = F_NXDOMAIN;
...@@ -171,7 +171,7 @@ search_servers (time_t now, struct all_addr **addrpp, ...@@ -171,7 +171,7 @@ search_servers (time_t now, struct all_addr **addrpp,
} }
else if (obj->domain_flags & SERV_LITERAL_ADDRESS) else if (obj->domain_flags & SERV_LITERAL_ADDRESS)
{ {
// --address and AF matches /* --address and AF matches */
sflag = obj->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6; sflag = obj->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
if (sflag & qtype) if (sflag & qtype)
{ {
...@@ -187,8 +187,8 @@ search_servers (time_t now, struct all_addr **addrpp, ...@@ -187,8 +187,8 @@ search_servers (time_t now, struct all_addr **addrpp,
} }
else if (obj->domain_flags & SERV_USE_RESOLV) else if (obj->domain_flags & SERV_USE_RESOLV)
{ {
// --server=8.8.8.8 /* --server=8.8.8.8 */
*type = 0; // use normal server *type = 0; /* use normal server */
*fwdserv = NULL; *fwdserv = NULL;
} }
...@@ -200,7 +200,7 @@ search_servers (time_t now, struct all_addr **addrpp, ...@@ -200,7 +200,7 @@ search_servers (time_t now, struct all_addr **addrpp,
} }
else else
{ {
*type = 0; /* use normal servers for this domain */ *type = 0; /* use normal servers for this domain */
*fwdserv = NULL; *fwdserv = NULL;
} }
...@@ -414,7 +414,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, ...@@ -414,7 +414,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
} }
#endif #endif
// we have the server for our domain by lookup daemon->dh_special_domains /* we have the server for our domain by lookup
* daemon->htree_special_domains */
int fd; int fd;
/* didn't find a server matches query domain */ /* didn't find a server matches query domain */
...@@ -464,7 +465,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, ...@@ -464,7 +465,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
#endif #endif
} }
//TODO how to retry here? //TODO are we retry correctly here?
if (sendto (fd, (char *) header, plen, 0, if (sendto (fd, (char *) header, plen, 0,
&fwdserv->addr.sa, sa_len (&fwdserv->addr)) == -1) &fwdserv->addr.sa, sa_len (&fwdserv->addr)) == -1)
{ {
...@@ -519,19 +520,19 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server ...@@ -519,19 +520,19 @@ 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 dict_node *np; struct htree_node *np;
struct ipsets_names *obj; struct ipsets_names *obj;
(void)ad_reqd; (void)ad_reqd;
(void) do_bit; (void) do_bit;
#ifdef HAVE_IPSET #ifdef HAVE_IPSET
if (daemon->dh_ipsets && extract_request(header, n, daemon->namebuff, NULL)) if (daemon->htree_ipsets && extract_request(header, n, daemon->namebuff, NULL))
{ {
np = match_domain(daemon->dh_ipsets, daemon->namebuff); np = domain_match(daemon->htree_ipsets, daemon->namebuff);
if (np != NULL) if (np != NULL)
{ {
obj = (struct ipsets_names *) np->obj; obj = (struct ipsets_names *) np->ptr;
sets = obj->sets; sets = obj->sets;
} }
} }
......
/* dict.c is Copyright (c) 2015 Chen Wei <weichen302@gmail.com> /* htree.c Chen Wei <weichen302@gmail.com>
Use cascade of open addressing hash tables to store config options that Use cascade of open addressing hash tables to store config options that
involve domain names. involve domain names.
...@@ -26,9 +26,6 @@ ...@@ -26,9 +26,6 @@
values are compared first, only if they are match, should the more values are compared first, only if they are match, should the more
expensive string comparison be used to confirm the search. expensive string comparison be used to confirm the search.
The search should take constant time regardless the size of --ipset and
--server rules.
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -46,17 +43,17 @@ ...@@ -46,17 +43,17 @@
#include "dnsmasq.h" #include "dnsmasq.h"
#define OPEN_ADDRESSING_MAXJUMP 7 /* no reason, just like 7 */ #define OPEN_ADDRESSING_MAXPROBE 7
#define OPEN_ADDRESSING_DEFAULT_SLOT 4 #define OPEN_ADDRESSING_DEFAULT_SIZE 4
#define FNV1_32A_INIT ((uint32_t)0x811c9dc5) #define FNV1_32A_INIT ((uint32_t)0x811c9dc5)
#define max(A, B) ((A) > (B) ? (A) : (B)) #define max(A, B) ((A) > (B) ? (A) : (B))
static char buf[MAXDNAME]; static char buf[MAXDNAME];
/* prototypes */ /* prototypes */
static struct dict_node *lookup_dictnode (struct dict_node *node, char *label); static struct htree_node *htree_find (struct htree_node *node, char *label);
static void add_dicttree (struct dict_node *node, struct dict_node *sub); static void htree_add (struct htree_node *node, struct htree_node *sub);
static void upsize_dicttree (struct dict_node *np); static void htree_upsizing (struct htree_node *np);
static inline void normalize_domain_name (char *dst, char *src, int len); static inline void normalize_domain_name (char *dst, char *src, int len);
/* hash function 1 for double hashing /* hash function 1 for double hashing
...@@ -90,7 +87,7 @@ static inline uint32_t dblhash_2 (char *key) ...@@ -90,7 +87,7 @@ static inline uint32_t dblhash_2 (char *key)
} }
/* convert domain to lower cases, remove leading blank, leading and trailing /* convert domain to lower cases, remove leading blank, leading and trailing
* dot, string end with \0 */ * dot. End string with \0 */
static inline void normalize_domain_name (char *d, char *s, int len) static inline void normalize_domain_name (char *d, char *s, int len)
{ {
int i; int i;
...@@ -122,28 +119,28 @@ static inline void normalize_domain_name (char *d, char *s, int len) ...@@ -122,28 +119,28 @@ static inline void normalize_domain_name (char *d, char *s, int len)
d[i] = '\0'; d[i] = '\0';
} }
struct dict_node * init_sub_dictnode (struct dict_node *node) struct htree_node * htree_init_sub (struct htree_node *node)
{ {
unsigned n; unsigned n;
if (node->sub != NULL) if (node->sub != NULL)
return node; return node;
node->sub_slots = OPEN_ADDRESSING_DEFAULT_SLOT; node->sub_size = OPEN_ADDRESSING_DEFAULT_SIZE;
node->sub_loadmax = node->sub_slots * 3 / 4; // loading factor 0.75 node->sub_loadmax = node->sub_size * 3 / 4; /* max loading factor 0.75 */
node->sub = safe_malloc (node->sub_slots * sizeof (struct dict_node *)); node->sub = safe_malloc (node->sub_size * sizeof (struct htree_node *));
for (n = 0; n < node->sub_slots; n++) for (n = 0; n < node->sub_size; n++)
node->sub[n] = NULL; node->sub[n] = NULL;
return node; return node;
} }
/* allocate and initialize a new node */ /* allocate and initialize a new node */
struct dict_node * new_dictnode (char *label, int label_len) struct htree_node * htree_new_node (char *label, int label_len)
{ {
struct dict_node *node; struct htree_node *node;
node = safe_malloc (sizeof (struct dict_node)); node = safe_malloc (sizeof (struct htree_node));
if (node == NULL) if (node == NULL)
return NULL; return NULL;
...@@ -161,59 +158,59 @@ struct dict_node * new_dictnode (char *label, int label_len) ...@@ -161,59 +158,59 @@ struct dict_node * new_dictnode (char *label, int label_len)
} }
node->sub_count = 0; node->sub_count = 0;
node->sub_slots = 0; node->sub_size = 0;
node->sub_loadmax = 0; node->sub_loadmax = 0;
node->sub_maxjump = 0; node->sub_maxprobe = 0;
node->sub = NULL; node->sub = NULL;
node->obj = NULL; node->ptr = NULL;
return node; return node;
} }
/* double the slots of dns node, it calls with add_dicttree each other /* double the size of hash table attached to a htree_node, it calls with
* the table size starts with 2^2, so that the new size remains 2^x, the * htree_add with each other. The table size starts with 2^2, so that the new
* double hash used is choosed to work with 2^n slots and perform well */ * size remains 2^x, the double hash used is chosen to work with 2^n slots */
static void upsize_dicttree (struct dict_node *np) static void htree_upsizing (struct htree_node *np)
{ {
struct dict_node **oldnodes; struct htree_node **oldnodes;
unsigned i, oldsize; unsigned i, oldsize;
oldsize = np->sub_slots; oldsize = np->sub_size;
oldnodes = np->sub; oldnodes = np->sub;
np->sub_slots = oldsize * 2; np->sub_size = oldsize * 2;
np->sub_loadmax = np->sub_slots * 3 / 4; np->sub_loadmax = np->sub_size * 3 / 4;
np->sub_count = 0; np->sub_count = 0;
np->sub_maxjump = 0; np->sub_maxprobe = 0;
np->sub = safe_malloc (np->sub_slots * sizeof (struct dict_node *)); np->sub = safe_malloc (np->sub_size * sizeof (struct htree_node *));
for (i = 0; i < np->sub_slots; i++) for (i = 0; i < np->sub_size; i++)
np->sub[i] = NULL; np->sub[i] = NULL;
for (i = 0; i < oldsize; i++) for (i = 0; i < oldsize; i++)
{ {
if (oldnodes[i] != NULL) if (oldnodes[i] != NULL)
{ {
add_dicttree (np, oldnodes[i]); htree_add (np, oldnodes[i]);
} }
} }
free (oldnodes); free (oldnodes);
} }
/* add a sub-node, upsize if needed, calls with upsize_dicttree each other */ /* add a sub-node, upsize if needed, calls with htree_upsizing with each other */
static void add_dicttree (struct dict_node *node, struct dict_node *sub) static void htree_add (struct htree_node *node, struct htree_node *sub)
{ {
int n; int n;
uint32_t dh, idx; uint32_t dh, idx;
if (node->sub == NULL) if (node->sub == NULL)
init_sub_dictnode (node); htree_init_sub (node);
n = 0; n = 0;
dh = sub->h1; dh = sub->h1;
while (1) while (1)
{ {
/* eq to dh % node->sub_slots, since sub_slots is power of 2*/ /* eq to dh % node->sub_size, since sub_size is power of 2*/
idx = dh & (node->sub_slots - 1); idx = dh & (node->sub_size - 1);
if (node->sub[idx] == NULL) if (node->sub[idx] == NULL)
{ {
node->sub[idx] = sub; node->sub[idx] = sub;
...@@ -227,63 +224,56 @@ static void add_dicttree (struct dict_node *node, struct dict_node *sub) ...@@ -227,63 +224,56 @@ static void add_dicttree (struct dict_node *node, struct dict_node *sub)
} }
} }
node->sub_maxjump = max (n, node->sub_maxjump); node->sub_maxprobe = max (n, node->sub_maxprobe);
/* If it takes a lots of jumps to find an empty slot, or the used slots /*
* close to loading max, upsize the table */ * If it takes a lots of probes to find an empty slot, or the used slots
if (node->sub_maxjump > OPEN_ADDRESSING_MAXJUMP || * close to loading max, upsize the table
*/
if (node->sub_maxprobe > OPEN_ADDRESSING_MAXPROBE ||
node->sub_count > node->sub_loadmax) node->sub_count > node->sub_loadmax)
{ {
upsize_dicttree (node); htree_upsizing (node);
} }
return; return;
} }
/* add a new subnode to node, or update the attr of the subnode with same struct htree_node *htree_find_or_add (struct htree_node *node, char *label)
* label
* return the subnode */
struct dict_node *add_or_lookup_dictnode (struct dict_node *node, char *label)
{ {
struct dict_node *np; struct htree_node *np;
if ((np = lookup_dictnode (node, label)) == NULL) if ((np = htree_find (node, label)) == NULL)
{ {
if (node->sub == NULL) if (node->sub == NULL)
{ htree_init_sub (node);
init_sub_dictnode (node); np = htree_new_node (label, strlen (label));
} htree_add (node, np);
np = new_dictnode (label, strlen (label));
add_dicttree (node, np);
} }
return np; return np;
} }
/* lookup the label in node's sub, return pointer if found, NULL if not */ /* lookup the label in node's sub, return the pointer, NULL if not found */
static struct dict_node *lookup_dictnode (struct dict_node *node, char *label) static struct htree_node *htree_find (struct htree_node *node, char *label)
{ {
uint32_t h1, h2, dh, idx; uint32_t h1, h2, dh, idx;
struct dict_node *np; struct htree_node *np;
/* this domain doesn't have sub-domains */ /* this domain doesn't have sub-domains */
if (node->sub == NULL) if (node->sub == NULL)
{ return NULL;
return NULL;
}
dh = h1 = dblhash_1 (label); dh = h1 = dblhash_1 (label);
h2 = dblhash_2 (label); h2 = dblhash_2 (label);
idx = dh & (node->sub_slots - 1); idx = dh & (node->sub_size - 1);
while ((np = node->sub[idx]) != NULL) while ((np = node->sub[idx]) != NULL)
{ {
if (np->h1 == h1 && np->h2 == h2) if (np->h1 == h1 && np->h2 == h2)
if (strcmp (np->label, label) == 0) if (strcmp (np->label, label) == 0)
{ return np;
return np;
}
dh += h2; dh += h2;
idx = dh & (node->sub_slots - 1); idx = dh & (node->sub_size - 1);
} }
return NULL; return NULL;
...@@ -291,16 +281,16 @@ static struct dict_node *lookup_dictnode (struct dict_node *node, char *label) ...@@ -291,16 +281,16 @@ static struct dict_node *lookup_dictnode (struct dict_node *node, char *label)
/* look up the whole domain pattern by step over DNS name hierarchy top down. /* 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 * for example, if the pattern is cn.debian.org, the lookup will start with
* org, then debian, then cn */ * org, then debian, then cn. The longest pattern wins. */
struct dict_node * match_domain(struct dict_node *root, char *domain) struct htree_node * domain_match(struct htree_node *root, char *domain)
{ {
char *labels[MAXLABELS]; char *labels[MAXLABELS];
int i, label_num; int i, label_num;
int len = (int) sizeof(buf); int len = (int) sizeof(buf);
struct dict_node *node, *res; struct htree_node *node, *res;
if (root == NULL) if (root == NULL)
return NULL; return NULL;
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
normalize_domain_name (buf, domain, len); normalize_domain_name (buf, domain, len);
...@@ -325,69 +315,27 @@ struct dict_node * match_domain(struct dict_node *root, char *domain) ...@@ -325,69 +315,27 @@ struct dict_node * match_domain(struct dict_node *root, char *domain)
res = NULL; res = NULL;
for (i = label_num - 1; i >= 0; i--) for (i = label_num - 1; i >= 0; i--)
{ {
node = lookup_dictnode (node, labels[i]); node = htree_find (node, labels[i]);
/* match longest pattern, e.g. for pattern debian.org and cn.debian.org,
* domain name ftp.cn.debian.org will match pattern cn.debian.org */
if (node == NULL) if (node == NULL)
break; break;
if (node->obj != NULL) /* repeatedly overwrite with node that has option set while walk down the
res = node; * domain name tree to match config option with longest pattern */
if (node->ptr != NULL)
res = node;
} }
if (res == NULL)
return NULL;
return res; return res;
} }
/* look up the whole domain pattern by step over DNS name hierarchy top down. /* add a domain pattern in the form of debian.org to root or find the node
* for example, if the pattern is cn.debian.org, the lookup will start with * match the domain pattern (for modify) */
* org, then debian, then cn */ struct htree_node *domain_find_or_add (struct htree_node *root, char *domain)
struct dict_node * lookup_domain (struct dict_node *root, char *domain)
{
char *labels[MAXLABELS];
int i, label_num;
int len = (int) sizeof(buf);
struct dict_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 && node != NULL; i--)
{
node = lookup_dictnode (node, labels[i]);
}
return i == -1 ? node : NULL;
}
/* add a domain pattern in the form of debian.org to root
* return the node with lowest hierarchy */
struct dict_node *add_or_lookup_domain (struct dict_node *root, char *domain)
{ {
char *labels[MAXLABELS]; char *labels[MAXLABELS];
int i, label_num; int i, label_num;
int len = (int) sizeof(buf); int len = (int) sizeof(buf);
struct dict_node *node; struct htree_node *node;
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
normalize_domain_name (buf, domain, len); normalize_domain_name (buf, domain, len);
...@@ -409,22 +357,20 @@ struct dict_node *add_or_lookup_domain (struct dict_node *root, char *domain) ...@@ -409,22 +357,20 @@ struct dict_node *add_or_lookup_domain (struct dict_node *root, char *domain)
node = root; node = root;
for (i = label_num - 1; i >= 0; i--) for (i = label_num - 1; i >= 0; i--)
{ node = htree_find_or_add (node, labels[i]);
node = add_or_lookup_dictnode (node, labels[i]);
}
return node; return node;
} }
/* free node and all sub-nodes recursively. Unused. */ /* free node and all sub-nodes recursively. Unused. */
void free_dicttree (struct dict_node *node) void htree_free (struct htree_node *node)
{ {
struct dict_node *np; struct htree_node *np;
unsigned i; unsigned i;
if (node->sub_count > 0) if (node->sub_count > 0)
{ {
for (i = 0; i < node->sub_slots; i++) for (i = 0; i < node->sub_size; i++)
{ {
np = node->sub[i]; np = node->sub[i];
if (np != NULL) if (np != NULL)
...@@ -432,10 +378,10 @@ void free_dicttree (struct dict_node *node) ...@@ -432,10 +378,10 @@ void free_dicttree (struct dict_node *node)
if (np->label != NULL) if (np->label != NULL)
free (np->label); free (np->label);
if (np->obj != NULL) if (np->ptr != NULL)
free (np->obj); free (np->ptr);
free_dicttree (np); htree_free (np);
} }
} }
free (node->sub); free (node->sub);
...@@ -476,7 +422,7 @@ static inline struct server *serverdup(struct server *src) ...@@ -476,7 +422,7 @@ static inline struct server *serverdup(struct server *src)
* servers in daemon->servers link list. If no match found, then insert a new * servers in daemon->servers link list. If no match found, then insert a new
* server * server
* *
* Return the lookup result or the newly created server*/ * Return the lookup result or the newly created server */
struct server *lookup_or_install_new_server(struct server *serv) struct server *lookup_or_install_new_server(struct server *serv)
{ {
struct server *res; struct server *res;
...@@ -496,13 +442,11 @@ struct server *lookup_or_install_new_server(struct server *serv) ...@@ -496,13 +442,11 @@ struct server *lookup_or_install_new_server(struct server *serv)
return res; return res;
} }
/* print the daemon->dh_special_domains tree recursively /* print the daemon->htree_special_domains tree recursively */
* void print_server_special_domains (struct htree_node *node,
* do we really need it? */
void print_server_special_domains (struct dict_node *node,
char *parents[], int current_level) char *parents[], int current_level)
{ {
struct dict_node *np; struct htree_node *np;
struct special_domain *obj; struct special_domain *obj;
char buf[MAXDNAME]; char buf[MAXDNAME];
char ip_buf[16]; char ip_buf[16];
...@@ -514,9 +458,9 @@ void print_server_special_domains (struct dict_node *node, ...@@ -514,9 +458,9 @@ void print_server_special_domains (struct dict_node *node,
if (node->label != NULL) if (node->label != NULL)
{ {
parents[level] = node->label; parents[level] = node->label;
if (node->obj != NULL) if (node->ptr != NULL)
{ {
obj = (struct special_domain *) node->obj; obj = (struct special_domain *) node->ptr;
if (obj->domain_flags & SERV_HAS_DOMAIN) if (obj->domain_flags & SERV_HAS_DOMAIN)
{ {
memset (buf, 0, MAXDNAME); memset (buf, 0, MAXDNAME);
...@@ -535,7 +479,7 @@ void print_server_special_domains (struct dict_node *node, ...@@ -535,7 +479,7 @@ void print_server_special_domains (struct dict_node *node,
if (node->sub_count > 0) if (node->sub_count > 0)
{ {
for (i = 0; i < node->sub_slots; i++) for (i = 0; i < node->sub_size; i++)
if ((np = node->sub[i]) != NULL) if ((np = node->sub[i]) != NULL)
print_server_special_domains (np, parents, level); print_server_special_domains (np, parents, level);
} }
......
...@@ -1423,7 +1423,7 @@ void check_servers(void) ...@@ -1423,7 +1423,7 @@ void check_servers(void)
enumerate_interfaces(0); enumerate_interfaces(0);
char *levels[MAXLABELS + 1]; /* the root node starts at 1 */ char *levels[MAXLABELS + 1]; /* the root node starts at 1 */
struct dict_node *root = daemon->dh_special_domains; struct htree_node *root = daemon->htree_special_domains;
print_server_special_domains(root, levels, 0); print_server_special_domains(root, levels, 0);
for (serv = daemon->servers; serv; serv = serv->next) for (serv = daemon->servers; serv; serv = serv->next)
......
...@@ -2228,7 +2228,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -2228,7 +2228,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
char *start_addr, *s; char *start_addr, *s;
char *err; char *err;
struct server newserv; struct server newserv;
struct dict_node *np = NULL; struct htree_node *np = NULL;
struct special_domain *obj; struct special_domain *obj;
memset (&newserv, 0, sizeof (struct server)); memset (&newserv, 0, sizeof (struct server));
...@@ -2238,23 +2238,20 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -2238,23 +2238,20 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (arg == NULL) if (arg == NULL)
break; break;
if (daemon->dh_special_domains == NULL) if (daemon->htree_special_domains == NULL)
daemon->dh_special_domains = new_dictnode (NULL, 0); daemon->htree_special_domains = htree_new_node (NULL, 0);
// scan the address part first /* scan the address part first
// --xxxx=/example.org/ample.com/temple.net/address-of-server * --xxxx=/example.org/ample.com/temple.net/address-of-server
// ^ * ^ */
start_addr = NULL; start_addr = NULL;
if (strchr (arg, '/') == NULL) if (strchr (arg, '/') == NULL)
{ {
// --xxxx=example.org (only availabe for --rebind-domain-ok) /* --xxxx=example.org (only availabe for --rebind-domain-ok) */
if (option == LOPT_NO_REBIND) if (option == LOPT_NO_REBIND)
newserv.flags |= SERV_NO_REBIND; newserv.flags |= SERV_NO_REBIND;
else if (option == 'S') else if (option == 'S')
{ start_addr = arg; /* --server=8.8.8.8 */
// --server=8.8.8.8
start_addr = arg;
}
} }
else else
...@@ -2273,10 +2270,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -2273,10 +2270,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (*start_addr == '#') if (*start_addr == '#')
{ {
newserv.flags |= SERV_USE_RESOLV; newserv.flags |= SERV_USE_RESOLV;
} }
else if (*start_addr == '\0')
/* --xxxx=/example.org/here-is-empty */ /* --xxxx=/example.org/here-is-empty */
else if (*start_addr == '\0')
{ {
/* give --server domain but no ip means the domain is local and /* give --server domain but no ip means the domain is local and
* it may answer queries from /etc/hosts or DHCP but should * it may answer queries from /etc/hosts or DHCP but should
...@@ -2287,10 +2284,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -2287,10 +2284,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (option == 'A') if (option == 'A')
ret_err ("--address must specify address"); ret_err ("--address must specify address");
} }
/* --xxxx=/example.org/8.8.8.8#53@source-ip|interface#port
* --xxxx=8.8.8.8 */
else else
{ {
/* --xxxx=/example.org/8.8.8.8#53@source-ip|interface#port
* --xxxx=8.8.8.8 */
err = err =
parse_server (start_addr, &newserv.addr, &newserv.source_addr, parse_server (start_addr, &newserv.addr, &newserv.source_addr,
newserv.interface, &newserv.flags); newserv.interface, &newserv.flags);
...@@ -2300,21 +2298,21 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -2300,21 +2298,21 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
} }
} }
// --server /* --server */
if (servers_only && option == 'S') if (servers_only && option == 'S')
newserv.flags |= SERV_FROM_FILE; newserv.flags |= SERV_FROM_FILE;
// --rebind-domain-ok /* --rebind-domain-ok */
if (option == LOPT_NO_REBIND) if (option == LOPT_NO_REBIND)
newserv.flags |= SERV_NO_REBIND; newserv.flags |= SERV_NO_REBIND;
// --address will be handled inside the domain dict_node /* --address will be handled inside the domain htree_node */
// the arg pattern can be /* the arg pattern can be
// --xxxx=example.org (only availabe for --rebind-domain-ok) or * --xxxx=example.org (only availabe for --rebind-domain-ok) or
// --xxxx=/example.org/ or * --xxxx=/example.org/ or
// --xxxx=/example.org/ample.com/temple.net/ * --xxxx=/example.org/ample.com/temple.net/ */
if (*arg == '/' || option == LOPT_NO_REBIND) if (*arg == '/' || option == LOPT_NO_REBIND)
{ {
int rebind = !(*arg == '/'); int rebind = !(*arg == '/');
...@@ -2328,15 +2326,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -2328,15 +2326,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
while (*arg == '.') while (*arg == '.')
arg++; arg++;
// wrong config option --xxxx=/./1.2.3.4 /* wrong config option --xxxx=/./1.2.3.4 */
if (strlen (arg) == 0) if (strlen (arg) == 0)
continue; continue;
// --address=/#/1.2.3.4 /* --address=/#/1.2.3.4
// use label in the root node to mark #(match all domains) * use label in the root node to mark #(match all domains) */
if (strcmp (arg, "#") == 0) if (strcmp (arg, "#") == 0)
{ {
np = daemon->dh_special_domains; np = daemon->htree_special_domains;
free(np->label); free(np->label);
np->label = strdup("#"); np->label = strdup("#");
} }
...@@ -2346,15 +2344,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -2346,15 +2344,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
} }
else else
{ {
np = add_or_lookup_domain(daemon->dh_special_domains, domain); np = domain_find_or_add(daemon->htree_special_domains, domain);
} }
free(domain); free(domain);
// domain unrecognizable /* domain unrecognizable */
if (np == NULL) if (np == NULL)
continue; continue;
if (np->obj == NULL) if (np->ptr == NULL)
{ {
obj = opt_malloc (sizeof (struct special_domain)); obj = opt_malloc (sizeof (struct special_domain));
memset (obj, 0, sizeof (struct special_domain)); memset (obj, 0, sizeof (struct special_domain));
...@@ -2362,7 +2360,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -2362,7 +2360,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
} }
else else
{ {
obj = (struct special_domain *) np->obj; obj = (struct special_domain *) np->ptr;
} }
obj->domain_flags = newserv.flags; obj->domain_flags = newserv.flags;
...@@ -2383,7 +2381,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -2383,7 +2381,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
{ {
/* pointer to one of servers in daemon->servers link /* pointer to one of servers in daemon->servers link
* list, no memory will be leaked if obj->server been * list, no memory will be leaked if obj->server been
* overwritten*/ * overwritten */
newserv.flags |= SERV_HAS_DOMAIN; newserv.flags |= SERV_HAS_DOMAIN;
obj->server = lookup_or_install_new_server (&newserv); obj->server = lookup_or_install_new_server (&newserv);
obj->server->domain = NULL; obj->server->domain = NULL;
...@@ -2393,8 +2391,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -2393,8 +2391,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (option == LOPT_NO_REBIND) if (option == LOPT_NO_REBIND)
{ {
// the rebind flag here instead of the one in struct server /* the rebind flag here instead of the one in struct server
// will be used by forward * will be used by forward */
obj->domain_flags |= SERV_NO_REBIND; obj->domain_flags |= SERV_NO_REBIND;
} }
...@@ -2403,15 +2401,14 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -2403,15 +2401,14 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
obj->domain_flags |= SERV_NO_ADDR; obj->domain_flags |= SERV_NO_ADDR;
} }
//newserv.flags |= domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS; np->ptr = (void *) obj;
np->obj = (void *) obj;
arg = end; arg = end;
if (rebind) if (rebind)
break; break;
} }
} }
// --server=8.8.8.8 /* --server=8.8.8.8 */
else if ((strchr (arg, '/') == NULL && option == 'S')) else if ((strchr (arg, '/') == NULL && option == 'S'))
{ {
lookup_or_install_new_server (&newserv); lookup_or_install_new_server (&newserv);
...@@ -2465,16 +2462,16 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -2465,16 +2462,16 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
char **sets, **sets_pos; char **sets, **sets_pos;
int sets_count = 0; int sets_count = 0;
unhide_metas (arg); unhide_metas (arg);
struct dict_node *np = NULL; struct htree_node *np = NULL;
struct dict_node *setname = NULL; struct htree_node *setname = NULL;
struct ipsets_names *obj; struct ipsets_names *obj;
char *domain = NULL; char *domain = NULL;
if (daemon->dh_ipsets == NULL) if (daemon->htree_ipsets == NULL)
daemon->dh_ipsets = new_dictnode (NULL, 0); daemon->htree_ipsets = htree_new_node (NULL, 0);
if (daemon->dh_ipset_names == NULL) if (daemon->htree_ipset_names == NULL)
daemon->dh_ipset_names = new_dictnode (NULL, 0); daemon->htree_ipset_names = htree_new_node (NULL, 0);
if (arg && *arg == '/') if (arg && *arg == '/')
{ {
...@@ -2493,7 +2490,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -2493,7 +2490,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
option = '?'; option = '?';
if (domain != NULL) if (domain != NULL)
np = add_or_lookup_domain (daemon->dh_ipsets, domain); np = domain_find_or_add (daemon->htree_ipsets, domain);
free(domain); free(domain);
arg = end; arg = end;
...@@ -2515,8 +2512,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -2515,8 +2512,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
do do
{ {
end = split (arg); end = split (arg);
// only store one copy of setname in daemon->dh_ipset_names // only store one copy of setname in daemon->htree_ipset_names
setname = add_or_lookup_dictnode(daemon->dh_ipset_names, arg); setname = htree_find_or_add(daemon->htree_ipset_names, arg);
*sets_pos++ = setname->label; *sets_pos++ = setname->label;
sets_count++; sets_count++;
arg = end; arg = end;
...@@ -2530,12 +2527,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -2530,12 +2527,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
obj = opt_malloc(sizeof(struct ipsets_names)); obj = opt_malloc(sizeof(struct ipsets_names));
obj->sets = sets; obj->sets = sets;
obj->count = sets_count; obj->count = sets_count;
if (np->obj != NULL) { if (np->ptr != NULL) {
old_obj = (struct ipsets_names *) np->obj; old_obj = (struct ipsets_names *) np->ptr;
free(old_obj->sets); free(old_obj->sets);
free(old_obj); free(old_obj);
} }
np->obj = (void *) obj; np->ptr = (void *) obj;
} }
break; break;
......
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