Commit 352d236d authored by Chen Wei's avatar Chen Wei

--server mod build successfully

parent c2a3d340
...@@ -25,8 +25,10 @@ ...@@ -25,8 +25,10 @@
#define FNV_32_PRIME ((uint32_t)0x01000193) #define FNV_32_PRIME ((uint32_t)0x01000193)
#define max(A, B) ((A) > (B) ? (A) : (B)) #define max(A, B) ((A) > (B) ? (A) : (B))
static char buf[MAXDNAME];
/* prototypes */ /* prototypes */
static struct dict_node *add_or_replace_dictnode (struct dict_node *node, char *label); static struct dict_node *add_or_lookup_dictnode (struct dict_node *node, char *label);
static struct dict_node *lookup_dictnode (struct dict_node *node, char *label); static struct dict_node *lookup_dictnode (struct dict_node *node, char *label);
static void add_dicttree (struct dict_node *node, struct dict_node *sub); static void add_dicttree (struct dict_node *node, struct dict_node *sub);
static void upsize_dicttree (struct dict_node *np); static void upsize_dicttree (struct dict_node *np);
...@@ -205,7 +207,7 @@ static void add_dicttree (struct dict_node *node, struct dict_node *sub) ...@@ -205,7 +207,7 @@ static void add_dicttree (struct dict_node *node, struct dict_node *sub)
/* add a new subnode to node, or update the attr of the subnode with same /* add a new subnode to node, or update the attr of the subnode with same
* label * label
* return the subnode */ * return the subnode */
static struct dict_node *add_or_replace_dictnode (struct dict_node *node, static struct dict_node *add_or_lookup_dictnode (struct dict_node *node,
char *label) char *label)
{ {
struct dict_node *np; struct dict_node *np;
...@@ -254,13 +256,11 @@ static struct dict_node *lookup_dictnode (struct dict_node *node, char *label) ...@@ -254,13 +256,11 @@ static struct dict_node *lookup_dictnode (struct dict_node *node, char *label)
return NULL; return NULL;
} }
/* 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 */
struct dict_node * match_domain_ipsets (struct dict_node *root, char *domain) struct dict_node * match_domain(struct dict_node *root, char *domain)
{ {
char buf[MAXDNAME];
char *labels[MAXLABELS]; char *labels[MAXLABELS];
int i, label_num; int i, label_num;
int len = strlen (domain); int len = strlen (domain);
...@@ -307,8 +307,8 @@ struct dict_node * match_domain_ipsets (struct dict_node *root, char *domain) ...@@ -307,8 +307,8 @@ struct dict_node * match_domain_ipsets (struct dict_node *root, char *domain)
res = node; res = node;
} }
if (res == NULL) if (res == NULL)
return NULL; return NULL;
return res; return res;
} }
...@@ -318,7 +318,6 @@ struct dict_node * match_domain_ipsets (struct dict_node *root, char *domain) ...@@ -318,7 +318,6 @@ struct dict_node * match_domain_ipsets (struct dict_node *root, char *domain)
* com, then google, then cache */ * com, then google, then cache */
struct dict_node * lookup_domain (struct dict_node *root, char *domain) struct dict_node * lookup_domain (struct dict_node *root, char *domain)
{ {
char buf[MAXDNAME];
char *labels[MAXLABELS]; char *labels[MAXLABELS];
int i, label_num; int i, label_num;
int len = strlen (domain); int len = strlen (domain);
...@@ -354,9 +353,8 @@ struct dict_node * lookup_domain (struct dict_node *root, char *domain) ...@@ -354,9 +353,8 @@ struct dict_node * lookup_domain (struct dict_node *root, char *domain)
/* add a domain pattern in the form of google.com to root /* add a domain pattern in the form of google.com to root
* return the node with lowest hierarchy */ * return the node with lowest hierarchy */
struct dict_node *add_domain (struct dict_node *root, char *domain) struct dict_node *add_or_lookup_domain (struct dict_node *root, char *domain)
{ {
char buf[MAXDNAME];
char *labels[MAXLABELS]; char *labels[MAXLABELS];
int i, label_num; int i, label_num;
int len = strlen (domain); int len = strlen (domain);
...@@ -383,7 +381,7 @@ struct dict_node *add_domain (struct dict_node *root, char *domain) ...@@ -383,7 +381,7 @@ struct dict_node *add_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 = add_or_replace_dictnode (node, labels[i]); node = add_or_lookup_dictnode (node, labels[i]);
} }
return node; return node;
...@@ -416,3 +414,54 @@ void free_dicttree (struct dict_node *node) ...@@ -416,3 +414,54 @@ void free_dicttree (struct dict_node *node)
free (node); free (node);
} }
/* temp area * */
/* 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 -1;
if (strncmp(s1->interface, s2->interface, IF_NAMESIZE + 1) != 0)
return -1;
if (s1->flags != s2->flags)
return -1;
return 0;
}
/* 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;
}
struct server *lookup_or_install_new_server(struct server *serv)
{
struct server *res;
res = NULL;
for (res = daemon->servers; res != NULL; res = res->next) {
if (is_same_server(res, serv))
break;
}
if (res == NULL) {
res = serverdup(serv);
res->next = daemon->servers;
daemon->servers = res;
}
return res;
}
...@@ -254,6 +254,9 @@ int main (int argc, char **argv) ...@@ -254,6 +254,9 @@ int main (int argc, char **argv)
ipset_init(); ipset_init();
#endif #endif
if (daemon->dh_special_domains == NULL)
daemon->dh_special_domains = new_dictnode(NULL, 0);
#if defined(HAVE_LINUX_NETWORK) #if defined(HAVE_LINUX_NETWORK)
netlink_init(); netlink_init();
#elif defined(HAVE_BSD_NETWORK) #elif defined(HAVE_BSD_NETWORK)
......
...@@ -534,6 +534,13 @@ struct dict_node { ...@@ -534,6 +534,13 @@ struct dict_node {
struct dict_node **sub; struct dict_node **sub;
}; };
struct special_domain {
struct server *server;
union mysockaddr addr;
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;
...@@ -965,8 +972,11 @@ extern struct daemon { ...@@ -965,8 +972,11 @@ extern struct daemon {
struct bogus_addr *bogus_addr, *ignore_addr; struct bogus_addr *bogus_addr, *ignore_addr;
struct server *servers; struct server *servers;
struct ipsets *ipsets; struct ipsets *ipsets;
struct dict_node *dh_ipsets; struct dict_node *dh_ipsets;
struct dict_node *dh_ipsets_names; struct dict_node *dh_ipsets_names;
struct dict_node *dh_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 */
...@@ -1392,8 +1402,9 @@ int add_to_ipset(const char *setname, const struct all_addr *ipaddr, int flags, ...@@ -1392,8 +1402,9 @@ int add_to_ipset(const char *setname, const struct all_addr *ipaddr, int flags,
/* dict.c */ /* dict.c */
struct dict_node *new_dictnode (char *label, int len); struct dict_node *new_dictnode (char *label, int len);
struct dict_node *lookup_domain(struct dict_node *root, char *domain); struct dict_node *lookup_domain(struct dict_node *root, char *domain);
struct dict_node *match_domain_ipsets (struct dict_node *root, char *domain); struct dict_node *match_domain(struct dict_node *root, char *domain);
struct dict_node *add_domain (struct dict_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);
void free_dicttree (struct dict_node *node); void free_dicttree (struct dict_node *node);
/* helper.c */ /* helper.c */
......
...@@ -120,102 +120,63 @@ int send_from(int fd, int nowild, char *packet, size_t len, ...@@ -120,102 +120,63 @@ int send_from(int fd, int nowild, char *packet, size_t len,
} }
static unsigned int search_servers(time_t now, struct all_addr **addrpp, static unsigned int search_servers(time_t now, struct all_addr **addrpp,
unsigned int qtype, char *qdomain, int *type, char **domain, int *norebind) unsigned int qtype, char *qdomain, int *type,
char **domain, int *norebind,
struct server **fwdserv)
{ {
/* If the query ends in the domain in one of our servers, set /* If the query ends in the domain in one of our servers, set
domain to point to that name. We find the largest match to allow both domain to point to that name. We find the largest match to allow both
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; struct server *serv;
struct server *serv; unsigned int flags = 0;
unsigned int flags = 0; unsigned int sflag;
struct dict_node *np;
for (serv = daemon->servers; serv; serv=serv->next) struct special_domain *obj;
/* domain matches take priority over NODOTS matches */
if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0) np = match_domain (daemon->dh_special_domains, qdomain);
if (np != NULL)
{ {
unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6; obj = (struct special_domain *) np->obj;
*type = SERV_FOR_NODOTS; serv = obj->server;
if (serv->flags & SERV_NO_ADDR) *type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV |
flags = F_NXDOMAIN; SERV_NO_REBIND);
else if (serv->flags & SERV_LITERAL_ADDRESS)
{ if (obj->domain_flags & SERV_NO_REBIND)
if (sflag & qtype) *norebind = 1;
{
flags = sflag; // no server, domain is local only
if (serv->addr.sa.sa_family == AF_INET) if (obj->domain_flags & SERV_NO_ADDR) {
*addrpp = (struct all_addr *)&serv->addr.in.sin_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 (serv->addr.sa.sa_family == AF_INET)
*addrpp = (struct all_addr *) &serv->addr.in.sin_addr;
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
else else
*addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr; *addrpp = (struct all_addr *) &serv->addr.in6.sin6_addr;
#endif #endif
} }
else if (!flags || (flags & F_NXDOMAIN)) } else {
flags = F_NOERR; *fwdserv = obj->server;
} flags = 0;
}
} }
//TODO add fast hash lookup else
else if (serv->flags & SERV_HAS_DOMAIN)
{ {
unsigned int domainlen = strlen(serv->domain); *type = 0; // use normal server
char *matchstart = qdomain + namelen - domainlen; *fwdserv = NULL;
if (namelen >= domainlen &&
hostname_isequal(matchstart, serv->domain) &&
(domainlen == 0 || namelen == domainlen || *(matchstart-1) == '.' ))
{
if (serv->flags & SERV_NO_REBIND)
*norebind = 1;
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))
{
if (!(sflag & qtype) && flags == 0)
continue;
}
else
{
if (flags & (F_IPV4 | F_IPV6))
continue;
}
}
if (domainlen >= matchlen)
{
*type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND);
*domain = serv->domain;
matchlen = domainlen;
if (serv->flags & SERV_NO_ADDR)
flags = F_NXDOMAIN;
else if (serv->flags & SERV_LITERAL_ADDRESS)
{
if (sflag & qtype)
{
flags = sflag;
if (serv->addr.sa.sa_family == AF_INET)
*addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
#ifdef HAVE_IPV6
else
*addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
#endif
}
else if (!flags || (flags & F_NXDOMAIN))
flags = F_NOERR;
}
else
flags = 0;
}
}
}
} }
/* have go through all servers in chain, now let's see what flag survive */
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 */
...@@ -241,6 +202,7 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, ...@@ -241,6 +202,7 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp,
return flags; return flags;
} }
//forward_query(-1, NULL, NULL, 0, header, nn, now, forward, 0, 0);
static int forward_query(int udpfd, union mysockaddr *udpaddr, static int forward_query(int udpfd, union mysockaddr *udpaddr,
struct all_addr *dst_addr, unsigned int dst_iface, struct all_addr *dst_addr, unsigned int dst_iface,
struct dns_header *header, size_t plen, time_t now, struct dns_header *header, size_t plen, time_t now,
...@@ -251,6 +213,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, ...@@ -251,6 +213,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
struct all_addr *addrp = NULL; struct all_addr *addrp = NULL;
unsigned int flags = 0; unsigned int flags = 0;
struct server *start = NULL; struct server *start = NULL;
struct server *fwdserv = NULL;
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
void *hash = hash_questions(header, plen, daemon->namebuff); void *hash = hash_questions(header, plen, daemon->namebuff);
#else #else
...@@ -322,7 +285,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, ...@@ -322,7 +285,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
else else
{ {
if (gotname) if (gotname)
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind); flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind, &fwdserv);
if (!flags && !(forward = get_new_frec(now, NULL, 0))) if (!flags && !(forward = get_new_frec(now, NULL, 0)))
/* table full - server failure. */ /* table full - server failure. */
...@@ -387,7 +350,6 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, ...@@ -387,7 +350,6 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
if (!flags && forward) if (!flags && forward)
{ {
struct server *firstsentto = start;
int forwarded = 0; int forwarded = 0;
/* If a query is retried, use the log_id for the retry when logging the answer. */ /* If a query is retried, use the log_id for the retry when logging the answer. */
...@@ -423,92 +385,75 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, ...@@ -423,92 +385,75 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
} }
#endif #endif
while (1) // we have the server for our domain by lookup daemon->dh_special_domains
{ int fd;
/* only send to servers dealing with our domain.
domain may be NULL, in which case server->domain
must be NULL also. */
if (type == (start->flags & SERV_TYPE) &&
(type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
!(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
{
int fd;
/* find server socket to use, may need to get random one. */ /* find server socket to use, may need to get random one. */
if (start->sfd) if (fwdserv->sfd)
fd = start->sfd->fd; fd = fwdserv->sfd->fd;
else else
{ {
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if (start->addr.sa.sa_family == AF_INET6) if (fwdserv->addr.sa.sa_family == AF_INET6)
{ {
if (!forward->rfd6 && if (forward->rfd6 == NULL)
!(forward->rfd6 = allocate_rfd(AF_INET6))) forward->rfd6 = allocate_rfd(AF_INET6);
break; daemon->rfd_save = forward->rfd6;
daemon->rfd_save = forward->rfd6; fd = forward->rfd6->fd;
fd = forward->rfd6->fd; }
} else
else
#endif #endif
{ {
if (!forward->rfd4 && if (forward->rfd4 == NULL)
!(forward->rfd4 = allocate_rfd(AF_INET))) forward->rfd4 = allocate_rfd(AF_INET);
break; daemon->rfd_save = forward->rfd4;
daemon->rfd_save = forward->rfd4; fd = forward->rfd4->fd;
fd = forward->rfd4->fd; }
}
#ifdef HAVE_CONNTRACK #ifdef HAVE_CONNTRACK
/* Copy connection mark of incoming query to outgoing connection. */ /* Copy connection mark of incoming query to outgoing connection. */
if (option_bool(OPT_CONNTRACK)) if (option_bool(OPT_CONNTRACK))
{ {
unsigned int mark; unsigned int mark;
if (get_incoming_mark(&forward->source, &forward->dest, 0, &mark)) if (get_incoming_mark(&forward->source, &forward->dest, 0, &mark))
setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int)); setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
} }
#endif #endif
} }
if (sendto(fd, (char *)header, plen, 0,
&start->addr.sa,
sa_len(&start->addr)) == -1)
{ if (sendto(fd, (char *)header, plen, 0,
if (retry_send()) &fwdserv->addr.sa,
continue; sa_len(&fwdserv->addr)) == -1)
} {
else retry_send();
{ }
/* Keep info in case we want to re-send this packet */
daemon->srv_save = start; else
daemon->packet_len = plen; {
/* Keep info in case we want to re-send this packet */
if (!gotname) daemon->srv_save = fwdserv;
strcpy(daemon->namebuff, "query"); daemon->packet_len = plen;
if (start->addr.sa.sa_family == AF_INET)
log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff, if (!gotname)
(struct all_addr *)&start->addr.in.sin_addr, NULL); strcpy(daemon->namebuff, "query");
if (fwdserv->addr.sa.sa_family == AF_INET)
log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&fwdserv->addr.in.sin_addr, NULL);
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
else else
log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff, log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&start->addr.in6.sin6_addr, NULL); (struct all_addr *)&fwdserv->addr.in6.sin6_addr, NULL);
#endif #endif
start->queries++; fwdserv->queries++;
forwarded = 1; forwarded = 1;
forward->sentto = start; forward->sentto = fwdserv;
if (!forward->forwardall) if (forward->forwardall)
break; forward->forwardall++;
forward->forwardall++; }
}
}
if (!(start = start->next))
start = daemon->servers;
if (start == firstsentto)
break;
}
if (forwarded) if (forwarded)
return 1; return 1;
...@@ -543,7 +488,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server ...@@ -543,7 +488,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
#ifdef HAVE_IPSET #ifdef HAVE_IPSET
if (daemon->dh_ipsets && extract_request(header, n, daemon->namebuff, NULL)) if (daemon->dh_ipsets && extract_request(header, n, daemon->namebuff, NULL))
{ {
np = match_domain_ipsets(daemon->dh_ipsets, daemon->namebuff); np = match_domain(daemon->dh_ipsets, daemon->namebuff);
if (np != NULL) if (np != NULL)
{ {
obj = (struct ipsets_names *) np->obj; obj = (struct ipsets_names *) np->obj;
...@@ -707,6 +652,7 @@ void reply_query(int fd, int family, time_t now) ...@@ -707,6 +652,7 @@ void reply_query(int fd, int family, time_t now)
if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) && if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
sockaddr_isequal(&server->addr, &serveraddr)) sockaddr_isequal(&server->addr, &serveraddr))
break; break;
/* TODO server may also come from the list for special domains */
if (!server) if (!server)
return; return;
...@@ -1677,7 +1623,7 @@ unsigned char *tcp_request(int confd, time_t now, ...@@ -1677,7 +1623,7 @@ unsigned char *tcp_request(int confd, time_t now,
/* largest field in header is 16-bits, so this is still sufficiently aligned */ /* largest field in header is 16-bits, so this is still sufficiently aligned */
struct dns_header *header = (struct dns_header *)payload; struct dns_header *header = (struct dns_header *)payload;
u16 *length = (u16 *)packet; u16 *length = (u16 *)packet;
struct server *last_server; struct server *last_server, *fwdserv;
struct in_addr dst_addr_4; struct in_addr dst_addr_4;
union mysockaddr peer_addr; union mysockaddr peer_addr;
socklen_t peer_len = sizeof(union mysockaddr); socklen_t peer_len = sizeof(union mysockaddr);
...@@ -1810,7 +1756,7 @@ unsigned char *tcp_request(int confd, time_t now, ...@@ -1810,7 +1756,7 @@ unsigned char *tcp_request(int confd, time_t now,
} }
if (gotname) if (gotname)
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind); flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind, &fwdserv);
if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server) if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
last_server = daemon->servers; last_server = daemon->servers;
......
...@@ -2210,11 +2210,74 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -2210,11 +2210,74 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case LOPT_NO_REBIND: /* --rebind-domain-ok */ case LOPT_NO_REBIND: /* --rebind-domain-ok */
//TODO fast hash lookup //TODO fast hash lookup
{ {
struct server *serv, *newlist = NULL;
unhide_metas(arg); unhide_metas(arg);
char *start_addr;
char *err;
struct server newlist;
struct dict_node *np;
struct special_domain *obj;
memset(&newlist, 0, sizeof(struct server));
#ifdef HAVE_LOOP
newlist.uid = rand32();
#endif
if (arg == NULL)
break;
// scan the address part first
// --xxxx=/example.org/ample.com/temple.net/address-of-server
// ^
start_addr = NULL;
if (strchr(arg, '/') == NULL) {
// --xxxx=example.org (only availabe for --rebind-domain-ok)
if (option == LOPT_NO_REBIND)
newlist.flags |= SERV_NO_REBIND;
else if (option == 'S')
// --server=8.8.8.8
start_addr = arg;
} else {
for (start_addr = arg;
(start_addr = strchr(start_addr, '/')) != NULL; ) ;
start_addr++;
}
/* --xxxx=/example.org/# , here "#" means use standard server*/
if (start_addr != NULL) {
if (*start_addr == '#') {
newlist.flags |= SERV_USE_RESOLV;
/* --xxxx=/example.org/here-is-empty */
} else if (*start_addr == '\0') {
if (!(newlist.flags & SERV_NO_REBIND))
newlist.flags |= SERV_NO_ADDR; /* no server */
} else {
/* --xxxx=/example.org/8.8.8.8#53@source-ip|interface#port */
err = parse_server(arg, &newlist.addr, &newlist.source_addr, newlist.interface, &newlist.flags);
if (err)
ret_err(err);
}
}
// --server
if (servers_only && option == 'S')
newlist.flags |= SERV_FROM_FILE;
if (arg && (*arg == '/' || option == LOPT_NO_REBIND)) // --rebind-domain-ok
if (option == LOPT_NO_REBIND)
newlist.flags |= SERV_NO_REBIND;
// --address will be handled inside the domain dict_node
// the arg pattern can be
// --xxxx=example.org (only availabe for --rebind-domain-ok) or
// --xxxx=/example.org/ or
// --xxxx=/example.org/ample.com/temple.net/
if (*arg == '/' || option == LOPT_NO_REBIND)
{ {
int rebind = !(*arg == '/'); int rebind = !(*arg == '/');
char *end = NULL; char *end = NULL;
...@@ -2230,75 +2293,49 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -2230,75 +2293,49 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
domain = ""; domain = "";
else if (strlen (arg) != 0 && !(domain = canonicalise_opt(arg))) else if (strlen (arg) != 0 && !(domain = canonicalise_opt(arg)))
option = '?'; option = '?';
serv = opt_malloc(sizeof(struct server));
memset(serv, 0, sizeof(struct server));
serv->next = newlist; np = add_or_lookup_domain(daemon->dh_special_domains, domain);
newlist = serv;
serv->domain = domain; if (np->obj == NULL) {
serv->flags = domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS; obj = opt_malloc(sizeof(struct special_domain));
memset(obj, 0, sizeof(struct special_domain));
obj->domain_flags = 0;
} else {
obj = (struct special_domain *) np->obj;
}
if (option == 'A') {
obj->server = NULL;
obj->domain_flags = SERV_LITERAL_ADDRESS;
memcpy(&obj->addr, &newlist.addr, sizeof(union mysockaddr));
} else if (option == 'S') {
// pointer to one of servers in daemon->servers link list,
// no memory is leaked if obj->server been overwritten
obj->server = lookup_or_install_new_server(&newlist);
}
if (option == LOPT_NO_REBIND) {
// the rebind flag here instead of the one in struct server
// will be used by forward
obj->domain_flags |= SERV_NO_REBIND;
}
if (option == LOPT_LOCAL) {
obj->domain_flags |= SERV_NO_ADDR;
}
//newlist.flags |= domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS;
np->obj = (void *) obj;
arg = end; arg = end;
if (rebind) if (rebind)
break; break;
} }
if (!newlist)
ret_err(gen_err);
}
else
{
newlist = opt_malloc(sizeof(struct server));
memset(newlist, 0, sizeof(struct server));
#ifdef HAVE_LOOP
newlist->uid = rand32();
#endif
}
if (servers_only && option == 'S')
newlist->flags |= SERV_FROM_FILE;
if (option == 'A')
{
newlist->flags |= SERV_LITERAL_ADDRESS;
if (!(newlist->flags & SERV_TYPE))
ret_err(gen_err);
}
else if (option == LOPT_NO_REBIND)
newlist->flags |= SERV_NO_REBIND;
if (!arg || !*arg)
{
if (!(newlist->flags & SERV_NO_REBIND))
newlist->flags |= SERV_NO_ADDR; /* no server */
if (newlist->flags & SERV_LITERAL_ADDRESS)
ret_err(gen_err);
} }
else if (strcmp(arg, "#") == 0) break;
{
newlist->flags |= SERV_USE_RESOLV; /* treat in ordinary way */
if (newlist->flags & SERV_LITERAL_ADDRESS)
ret_err(gen_err);
}
else
{
char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags);
if (err)
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;
break;
} }
case LOPT_REV_SERV: /* --rev-server */ case LOPT_REV_SERV: /* --rev-server */
{ {
char *string; char *string;
...@@ -2368,7 +2405,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -2368,7 +2405,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_domain (daemon->dh_ipsets, domain); np = add_or_lookup_domain (daemon->dh_ipsets, domain);
arg = end; arg = end;
} }
......
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