import of dnsmasq-2.9.tar.gz

This commit is contained in:
Simon Kelley
2004-06-22 20:23:33 +01:00
parent a222641cb0
commit de37951cf4
15 changed files with 470 additions and 235 deletions

View File

@@ -472,19 +472,21 @@ static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrl
struct crec *lookup = cache_find_by_name(NULL, cache->name.sname, 0, flags & (F_IPV4 | F_IPV6));
/* Remove duplicates in hosts files. */
if (lookup && (lookup->flags & F_HOSTS) &&
if (lookup && (lookup->flags & F_HOSTS) &&
memcmp(&lookup->addr, addr, addrlen) == 0)
free(cache);
else
{
/* Ensure there is only one address -> name mapping (first one trumps) */
if (cache_find_by_addr(NULL, addr, 0, flags & (F_IPV4 | F_IPV6)))
flags &= ~F_REVERSE;
cache->flags = flags;
memcpy(&cache->addr, addr, addrlen);
cache_hash(cache);
}
}
static void read_hostsfile(char *filename, int opts, char *buff, char *domain_suffix, unsigned short addn_flag)
static void read_hostsfile(char *filename, int opts, char *buff, char *domain_suffix, int is_addn)
{
FILE *f = fopen(filename, "r");
char *line;
@@ -529,6 +531,9 @@ static void read_hostsfile(char *filename, int opts, char *buff, char *domain_su
else
continue;
if (is_addn)
flags |= F_ADDN;
while ((token = strtok(NULL, " \t\n\r")) && (*token != '#'))
{
struct crec *cache;
@@ -543,16 +548,12 @@ static void read_hostsfile(char *filename, int opts, char *buff, char *domain_su
strcpy(cache->name.sname, token);
strcat(cache->name.sname, ".");
strcat(cache->name.sname, domain_suffix);
add_hosts_entry(cache, &addr, addrlen, flags | addn_flag);
/* Only first name is cannonical and used for reverse lookups */
flags &= ~F_REVERSE;
add_hosts_entry(cache, &addr, addrlen, flags);
}
if ((cache = malloc(sizeof(struct crec) + strlen(token)+1-SMALLDNAME)))
{
strcpy(cache->name.sname, token);
add_hosts_entry(cache, &addr, addrlen, flags | addn_flag);
/* Clear this here in case not done above. */
flags &= ~F_REVERSE;
add_hosts_entry(cache, &addr, addrlen, flags);
}
}
else
@@ -604,7 +605,7 @@ void cache_reload(int opts, char *buff, char *domain_suffix, char *addn_hosts)
read_hostsfile(HOSTSFILE, opts, buff, domain_suffix, 0);
if (addn_hosts)
{
read_hostsfile(addn_hosts, opts, buff, domain_suffix, F_ADDN);
read_hostsfile(addn_hosts, opts, buff, domain_suffix, 1);
addn_file = addn_hosts;
}
}

View File

@@ -12,7 +12,7 @@
/* Author's email: simon@thekelleys.org.uk */
#define VERSION "2.8"
#define VERSION "2.9"
#define FTABSIZ 150 /* max number of outstanding requests */
#define TIMEOUT 20 /* drop queries after TIMEOUT seconds */
@@ -59,17 +59,6 @@
#endif
/* determine if we can find the destination address of recieved packets
and set the source address of sent ones. If so, we can use one socket
bound to INADDR_ANY and cope with dynamically created interfaces.
Linux does this differently to FreeBSD. */
#if defined(IP_PKTINFO) || (defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR))
# define HAVE_UDP_SRC_DST
#else
# undef HAVE_UDP_SRC_DST
#endif
/* Decide if we're going to support IPv6 */
/* We assume that systems which don't have IPv6
headers don't have ntop and pton either */

View File

@@ -129,13 +129,9 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
return;
#else
if (!names || !names->name || names->next)
{
syslog(LOG_ERR, "must set exactly one interface on broken systems without IP_RECVIF");
return;
}
else
strcpy(ifr.ifr_name, names->name);
while (names->isloop)
names = names->next;
strcpy(ifr.ifr_name, names->name);
#endif
#ifdef HAVE_BPF
@@ -572,7 +568,7 @@ struct dhcp_config *dhcp_read_ethers(struct dhcp_config *configs, char *buff)
config->addr = addr;
}
config->flags |= CONFIG_HWADDR;
config->flags |= CONFIG_HWADDR | CONFIG_NOCLID;
memcpy(config->hwaddr, hwaddr, ETHER_ADDR_LEN);
count++;

View File

@@ -37,15 +37,16 @@ int main (int argc, char **argv)
int maxleases = MAXLEASES;
int query_port = 0;
int first_loop = 1;
int bind_fallback = 0;
unsigned long local_ttl = 0;
unsigned int options, min_leasetime;
char *runfile = RUNFILE;
time_t resolv_changed = 0;
time_t now, last = 0;
struct irec *interfaces = NULL;
struct listener *listener, *listeners;
struct listener *listener, *listeners = NULL;
struct doctor *doctors = NULL;
char *mxname = NULL;
struct mx_record *mxnames = NULL;
char *mxtarget = NULL;
char *lease_file = NULL;
char *addn_hosts = NULL;
@@ -106,7 +107,7 @@ int main (int argc, char **argv)
packet = safe_malloc(DNSMASQ_PACKETSZ);
dhcp_next_server.s_addr = 0;
options = read_opts(argc, argv, dnamebuff, &resolv, &mxname, &mxtarget, &lease_file,
options = read_opts(argc, argv, dnamebuff, &resolv, &mxnames, &mxtarget, &lease_file,
&username, &groupname, &domain_suffix, &runfile,
&if_names, &if_addrs, &if_except, &bogus_addr,
&serv_addrs, &cachesize, &port, &query_port, &local_ttl, &addn_hosts,
@@ -124,18 +125,41 @@ int main (int argc, char **argv)
die("ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h", NULL);
#endif
#ifndef HAVE_UDP_SRC_DST
/* if we cannot support binding the wildcard address, set the "bind only
interfaces in use" option */
options |= OPT_NOWILD;
#endif
interfaces = enumerate_interfaces(&if_names, &if_addrs, if_except, port);
if (options & OPT_NOWILD)
listeners = create_bound_listeners(interfaces);
else
listeners = create_wildcard_listeners(port);
if (!(options & OPT_NOWILD) && !(listeners = create_wildcard_listeners(port)))
{
bind_fallback = 1;
options |= OPT_NOWILD;
}
if (options & OPT_NOWILD)
{
struct iname *if_tmp;
listeners = create_bound_listeners(interfaces);
for (if_tmp = if_names; if_tmp; if_tmp = if_tmp->next)
if (if_tmp->name && !if_tmp->used)
die("unknown interface %s", if_tmp->name);
for (if_tmp = if_addrs; if_tmp; if_tmp = if_tmp->next)
if (!if_tmp->used)
{
char addrbuff[ADDRSTRLEN];
#ifdef HAVE_IPV6
if (if_tmp->addr.sa.sa_family == AF_INET)
inet_ntop(AF_INET, &if_tmp->addr.in.sin_addr,
addrbuff, ADDRSTRLEN);
else
inet_ntop(AF_INET6, &if_tmp->addr.in6.sin6_addr,
addrbuff, ADDRSTRLEN);
#else
strcpy(addrbuff, inet_ntoa(if_tmp->addr.in.sin_addr));
#endif
die("no interface with address %s", addrbuff);
}
}
forward_init(1);
cache_init(cachesize, options & OPT_LOG);
@@ -148,6 +172,15 @@ int main (int argc, char **argv)
if (dhcp)
{
#if !defined(IP_PKTINFO) && !defined(IP_RECVIF)
int c;
struct iname *tmp;
for (c = 0, tmp = if_names; tmp; tmp = tmp->next)
if (!tmp->isloop)
c++;
if (c != 1)
die("must set exactly one interface on broken systems without IP_RECVIF", NULL);
#endif
dhcp_init(&dhcpfd, &dhcp_raw_fd);
leasefd = lease_init(lease_file, domain_suffix, dnamebuff, packet, now, maxleases);
}
@@ -228,12 +261,9 @@ int main (int argc, char **argv)
else
syslog(LOG_INFO, "started, version %s cache disabled", VERSION);
if (options & OPT_LOCALMX)
syslog(LOG_INFO, "serving MX record for local hosts target %s", mxtarget);
else if (mxname)
syslog(LOG_INFO, "serving MX record for mailhost %s target %s",
mxname, mxtarget);
if (bind_fallback)
syslog(LOG_WARNING, "setting --bind-interfaces option because if OS limitations");
for (dhcp_tmp = dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
{
strcpy(dnamebuff, inet_ntoa(dhcp_tmp->start));
@@ -256,8 +286,9 @@ int main (int argc, char **argv)
if (getuid() == 0 || geteuid() == 0)
syslog(LOG_WARNING, "failed to drop root privs");
servers = last_server = check_servers(serv_addrs, interfaces, &sfds);
servers = check_servers(serv_addrs, interfaces, &sfds);
last_server = NULL;
while (sigterm == 0)
{
fd_set rset;
@@ -275,9 +306,11 @@ int main (int argc, char **argv)
lease_update_dns();
}
if (resolv && (options & OPT_NO_POLL))
servers = last_server =
check_servers(reload_servers(resolv->name, dnamebuff, servers, query_port),
interfaces, &sfds);
{
servers = check_servers(reload_servers(resolv->name, dnamebuff, servers, query_port),
interfaces, &sfds);
last_server = NULL;
}
sighup = 0;
}
@@ -373,7 +406,7 @@ int main (int argc, char **argv)
else
{
res->logged = 0;
if (statbuf.st_mtime > last_change)
if (difftime(statbuf.st_mtime, last_change) > 0.0)
{
last_change = statbuf.st_mtime;
latest = res;
@@ -382,20 +415,20 @@ int main (int argc, char **argv)
res = res->next;
}
if (latest && last_change > resolv_changed)
if (latest && difftime(last_change, resolv_changed) > 0.0)
{
resolv_changed = last_change;
servers = last_server =
check_servers(reload_servers(latest->name, dnamebuff, servers, query_port),
interfaces, &sfds);
servers = check_servers(reload_servers(latest->name, dnamebuff, servers, query_port),
interfaces, &sfds);
last_server = NULL;
}
}
}
for (serverfdp = sfds; serverfdp; serverfdp = serverfdp->next)
if (FD_ISSET(serverfdp->fd, &rset))
last_server = reply_query(serverfdp->fd, options, packet, now,
dnamebuff, last_server, bogus_addr, doctors);
last_server = reply_query(serverfdp, options, packet, now,
dnamebuff, servers, last_server, bogus_addr, doctors);
if (dhcp && FD_ISSET(dhcpfd, &rset))
dhcp_packet(dhcp, packet, dhcp_options, dhcp_configs, dhcp_vendors,
@@ -406,7 +439,7 @@ int main (int argc, char **argv)
for (listener = listeners; listener; listener = listener->next)
if (FD_ISSET(listener->fd, &rset))
last_server = receive_query(listener, packet,
mxname, mxtarget, options, now, local_ttl, dnamebuff,
mxnames, mxtarget, options, now, local_ttl, dnamebuff,
if_names, if_addrs, if_except, last_server, servers);
}

View File

@@ -56,7 +56,7 @@
#include <errno.h>
#include <pwd.h>
#include <grp.h>
#if defined(__OpenBSD__)
#if defined(__OpenBSD__) || defined(__NetBSD__)
# include <netinet/if_ether.h>
#else
# include <net/ethernet.h>
@@ -91,6 +91,7 @@
#define OPT_NODOTS_LOCAL 4096
#define OPT_NOWILD 8192
#define OPT_ETHERS 16384
#define OPT_RESOLV_DOMAIN 32768
struct all_addr {
union {
@@ -112,6 +113,11 @@ struct doctor {
struct doctor *next;
};
struct mx_record {
char *mxname, *mxtarget;
struct mx_record *next;
};
union bigname {
char name[MAXDNAME];
union bigname *next; /* freelist */
@@ -206,6 +212,7 @@ struct listener {
struct iname {
char *name;
union mysockaddr addr;
int isloop, used;
struct iname *next;
};
@@ -337,7 +344,7 @@ int setup_reply(HEADER *header, unsigned int qlen,
void extract_addresses(HEADER *header, unsigned int qlen, char *namebuff,
time_t now, struct doctor *doctors);
void extract_neg_addrs(HEADER *header, unsigned int qlen, char *namebuff, time_t now);
int answer_request(HEADER *header, char *limit, unsigned int qlen, char *mxname,
int answer_request(HEADER *header, char *limit, unsigned int qlen, struct mx_record *mxnames,
char *mxtarget, unsigned int options, time_t now, unsigned long local_ttl,
char *namebuff);
int check_for_bogus_wildcard(HEADER *header, unsigned int qlen, char *name,
@@ -360,7 +367,7 @@ int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
/* option.c */
unsigned int read_opts(int argc, char **argv, char *buff, struct resolvc **resolv_file,
char **mxname, char **mxtarget, char **lease_file,
struct mx_record **mxnames, char **mxtarget, char **lease_file,
char **username, char **groupname,
char **domain_suffix, char **runfile,
struct iname **if_names, struct iname **if_addrs, struct iname **if_except,
@@ -373,11 +380,11 @@ unsigned int read_opts(int argc, char **argv, char *buff, struct resolvc **resol
/* forward.c */
void forward_init(int first);
struct server *reply_query(int fd, int options, char *packet, time_t now,
char *dnamebuff, struct server *last_server,
struct server *reply_query(struct serverfd *sfd, int options, char *packet, time_t now,
char *dnamebuff, struct server *servers, struct server *last_server,
struct bogus_addr *bogus_nxdomain, struct doctor *doctors);
struct server *receive_query(struct listener *listen, char *packet, char *mxname,
struct server *receive_query(struct listener *listen, char *packet, struct mx_record *mxnames,
char *mxtarget, unsigned int options, time_t now,
unsigned long local_ttl, char *namebuff,
struct iname *names, struct iname *addrs, struct iname *except,

View File

@@ -120,22 +120,27 @@ static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
{
struct frec *forward;
char *domain = NULL;
int type = 0;
struct server *serv;
int forwardall = 0, type = 0;
struct all_addr *addrp = NULL;
unsigned short flags = 0;
unsigned short gotname = extract_request(header, (unsigned int)plen, dnamebuff);
struct server *start = NULL;
/* may be recursion not speced or no servers available. */
if (!header->rd || !servers)
forward = NULL;
else if ((forward = lookup_frec_by_sender(ntohs(header->id), udpaddr)))
{
/* retry on existing query, send to next server */
/* retry on existing query, send to all available servers */
domain = forward->sentto->domain;
if (!(options & OPT_ORDER))
{
forwardall = 1;
last_server = NULL;
}
type = forward->sentto->flags & SERV_TYPE;
if (!(forward->sentto = forward->sentto->next))
forward->sentto = servers; /* at end of list, recycle */
if (!(start = forward->sentto->next))
start = servers; /* at end of list, recycle */
header->id = htons(forward->new_id);
}
else
@@ -148,29 +153,25 @@ static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
unsigned int namelen = strlen(dnamebuff);
unsigned int matchlen = 0;
struct server *serv;
for (serv=servers; serv; serv=serv->next)
/* domain matches take priority over NODOTS matches */
if ((serv->flags & SERV_FOR_NODOTS) && type != SERV_HAS_DOMAIN && !strchr(dnamebuff, '.'))
{
if (serv->flags & SERV_LITERAL_ADDRESS)
unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
type = SERV_FOR_NODOTS;
flags = 0;
if ((serv->flags & SERV_LITERAL_ADDRESS) && (sflag & gotname))
{
/* flags gets set if server is in fact an answer */
unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
if (sflag & gotname) /* only OK if addrfamily == query */
{
type = SERV_FOR_NODOTS;
flags = sflag;
if (serv->addr.sa.sa_family == AF_INET)
addrp = (struct all_addr *)&serv->addr.in.sin_addr;
flags = sflag;
if (serv->addr.sa.sa_family == AF_INET)
addrp = (struct all_addr *)&serv->addr.in.sin_addr;
#ifdef HAVE_IPV6
else
addrp = (struct all_addr *)&serv->addr.in6.sin6_addr;
else
addrp = (struct all_addr *)&serv->addr.in6.sin6_addr;
#endif
}
}
else
flags = 0;
}
else if (serv->flags & SERV_HAS_DOMAIN)
{
@@ -179,29 +180,20 @@ static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
hostname_isequal(dnamebuff + namelen - domainlen, serv->domain) &&
domainlen >= matchlen)
{
if (serv->flags & SERV_LITERAL_ADDRESS)
{ /* flags gets set if server is in fact an answer */
unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
if ((sflag | F_QUERY ) & gotname) /* only OK if addrfamily == query */
{
type = SERV_HAS_DOMAIN;
flags = gotname;
domain = serv->domain;
matchlen = domainlen;
if (serv->addr.sa.sa_family == AF_INET)
addrp = (struct all_addr *)&serv->addr.in.sin_addr;
#ifdef HAVE_IPV6
else
addrp = (struct all_addr *)&serv->addr.in6.sin6_addr;
#endif
}
}
else
unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
type = SERV_HAS_DOMAIN;
domain = serv->domain;
matchlen = domainlen;
flags = 0;
if ((serv->flags & SERV_LITERAL_ADDRESS) && ((sflag | F_QUERY ) & gotname))
{
flags = 0; /* may be better match from previous literal */
domain = serv->domain;
matchlen = domainlen;
type = SERV_HAS_DOMAIN;
flags = gotname;
if (serv->addr.sa.sa_family == AF_INET)
addrp = (struct all_addr *)&serv->addr.in.sin_addr;
#ifdef HAVE_IPV6
else
addrp = (struct all_addr *)&serv->addr.in6.sin6_addr;
#endif
}
}
}
@@ -231,10 +223,13 @@ static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
otherwise, use the one last known to work. */
if (type != 0 || (options & OPT_ORDER))
forward->sentto = servers;
else
forward->sentto = last_server;
start = servers;
else if (!(start = last_server))
{
start = servers;
forwardall = 1;
}
forward->source = *udpaddr;
forward->dest = *dst_addr;
forward->new_id = get_id();
@@ -250,52 +245,52 @@ static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
if (!flags && forward)
{
struct server *firstsentto = forward->sentto;
struct server *firstsentto = start;
int forwarded = 0;
while (1)
{
int logflags = 0;
if (forward->sentto->addr.sa.sa_family == AF_INET)
{
logflags = F_SERVER | F_IPV4 | F_FORWARD;
addrp = (struct all_addr *)&forward->sentto->addr.in.sin_addr;
}
#ifdef HAVE_IPV6
else
{
logflags = F_SERVER | F_IPV6 | F_FORWARD;
addrp = (struct all_addr *)&forward->sentto->addr.in6.sin6_addr;
}
#endif
/* only send to servers dealing with our domain.
domain may be NULL, in which case server->domain
must be NULL also. */
if (type == (forward->sentto->flags & SERV_TYPE) &&
(type != SERV_HAS_DOMAIN || hostname_isequal(domain, forward->sentto->domain)))
if (type == (start->flags & SERV_TYPE) &&
(type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)))
{
if (forward->sentto->flags & SERV_NO_ADDR)
if (start->flags & SERV_NO_ADDR)
flags = F_NOERR; /* NULL servers are OK. */
else if (!(forward->sentto->flags & SERV_LITERAL_ADDRESS) &&
sendto(forward->sentto->sfd->fd, (char *)header, plen, 0,
&forward->sentto->addr.sa,
sa_len(&forward->sentto->addr)) != -1)
else if (!(start->flags & SERV_LITERAL_ADDRESS) &&
sendto(start->sfd->fd, (char *)header, plen, 0,
&start->addr.sa,
sa_len(&start->addr)) != -1)
{
log_query(logflags, gotname ? dnamebuff : "query", addrp);
/* for no-domain, don't update last_server */
return domain ? last_server : (forward->sentto->next ? forward->sentto->next : servers);
if (!gotname)
strcpy(dnamebuff, "query");
if (start->addr.sa.sa_family == AF_INET)
log_query(F_SERVER | F_IPV4 | F_FORWARD, dnamebuff,
(struct all_addr *)&start->addr.in.sin_addr);
#ifdef HAVE_IPV6
else
log_query(F_SERVER | F_IPV6 | F_FORWARD, dnamebuff,
(struct all_addr *)&start->addr.in6.sin6_addr);
#endif
forwarded = 1;
forward->sentto = start;
if (!forwardall)
break;
}
}
if (!(forward->sentto = forward->sentto->next))
forward->sentto = servers;
if (!(start = start->next))
start = servers;
/* check if we tried all without success */
if (forward->sentto == firstsentto)
if (start == firstsentto)
break;
}
if (forwarded)
return last_server;
/* could not send on, prepare to return */
header->id = htons(forward->orig_id);
forward->new_id = 0; /* cancel */
@@ -312,52 +307,81 @@ static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
}
/* returns new last_server */
struct server *reply_query(int fd, int options, char *packet, time_t now,
char *dnamebuff, struct server *last_server,
struct server *reply_query(struct serverfd *sfd, int options, char *packet, time_t now,
char *dnamebuff, struct server *servers, struct server *last_server,
struct bogus_addr *bogus_nxdomain, struct doctor *doctors)
{
/* packet from peer server, extract data for cache, and send to
original requester */
struct frec *forward;
HEADER *header;
int n = recv(fd, packet, PACKETSZ, 0);
union mysockaddr serveraddr;
socklen_t addrlen = sizeof(serveraddr);
int n = recvfrom(sfd->fd, packet, PACKETSZ, 0, &serveraddr.sa, &addrlen);
/* Determine the address of the server replying so that we can mark that as good */
serveraddr.sa.sa_family = sfd->source_addr.sa.sa_family;
#ifdef HAVE_IPV6
if (serveraddr.sa.sa_family == AF_INET6)
serveraddr.in6.sin6_flowinfo = htonl(0);
#endif
header = (HEADER *)packet;
if (n >= (int)sizeof(HEADER) && header->qr)
if (n >= (int)sizeof(HEADER) && header->qr && (forward = lookup_frec(ntohs(header->id))))
{
if ((forward = lookup_frec(ntohs(header->id))))
/* find good server by address if possible, otherwise assume the last one we sent to */
if ((forward->sentto->flags & SERV_TYPE) == 0)
{
if (header->rcode == NOERROR || header->rcode == NXDOMAIN)
{
if (!forward->sentto->domain)
last_server = forward->sentto; /* known good */
if (header->opcode == QUERY)
{
if (!(bogus_nxdomain &&
header->rcode == NOERROR &&
check_for_bogus_wildcard(header, (unsigned int)n, dnamebuff, bogus_nxdomain, now)))
{
if (header->rcode == NOERROR && ntohs(header->ancount) != 0)
extract_addresses(header, (unsigned int)n, dnamebuff, now, doctors);
else if (!(options & OPT_NO_NEG))
extract_neg_addrs(header, (unsigned int)n, dnamebuff, now);
}
}
}
header->id = htons(forward->orig_id);
/* There's no point returning an upstream reply marked as truncated,
since that will prod the resolver into moving to TCP - which we
don't support. */
header->tc = 0; /* goodbye truncate */
send_from(forward->fd, options & OPT_NOWILD, packet, n, &forward->source, &forward->dest);
forward->new_id = 0; /* cancel */
for (last_server = servers; last_server; last_server = last_server->next)
if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
sockaddr_isequal(&last_server->addr, &serveraddr))
break;
if (!last_server)
last_server = forward->sentto;
}
/* Complain loudly if the upstream server is non-recursive. */
if (!header->ra && header->rcode == NOERROR && ntohs(header->ancount) == 0)
{
char addrbuff[ADDRSTRLEN];
#ifdef HAVE_IPV6
if (serveraddr.sa.sa_family == AF_INET)
inet_ntop(AF_INET, &serveraddr.in.sin_addr, addrbuff, ADDRSTRLEN);
else if (serveraddr.sa.sa_family == AF_INET6)
inet_ntop(AF_INET6, &serveraddr.in6.sin6_addr, addrbuff, ADDRSTRLEN);
#else
strcpy(addrbuff, inet_ntoa(serveraddr.in.sin_addr));
#endif
syslog(LOG_WARNING, "nameserver %s refused to do a recursive query", addrbuff);
return NULL;
}
if ((header->rcode == NOERROR || header->rcode == NXDOMAIN) && header->opcode == QUERY)
{
if (!(bogus_nxdomain &&
header->rcode == NOERROR &&
check_for_bogus_wildcard(header, (unsigned int)n, dnamebuff, bogus_nxdomain, now)))
{
if (header->rcode == NOERROR && ntohs(header->ancount) != 0)
extract_addresses(header, (unsigned int)n, dnamebuff, now, doctors);
else if (!(options & OPT_NO_NEG))
extract_neg_addrs(header, (unsigned int)n, dnamebuff, now);
}
}
header->id = htons(forward->orig_id);
/* There's no point returning an upstream reply marked as truncated,
since that will prod the resolver into moving to TCP - which we
don't support. */
header->tc = 0; /* goodbye truncate */
send_from(forward->fd, options & OPT_NOWILD, packet, n, &forward->source, &forward->dest);
forward->new_id = 0; /* cancel */
}
return last_server;
}
struct server *receive_query(struct listener *listen, char *packet, char *mxname,
struct server *receive_query(struct listener *listen, char *packet, struct mx_record *mxnames,
char *mxtarget, unsigned int options, time_t now,
unsigned long local_ttl, char *namebuff,
struct iname *names, struct iname *addrs, struct iname *except,
@@ -395,7 +419,8 @@ struct server *receive_query(struct listener *listen, char *packet, char *mxname
msg.msg_iov = iov;
msg.msg_iovlen = 1;
n = recvmsg(listen->fd, &msg, 0);
if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
return last_server;
source_addr.sa.sa_family = listen->family;
#ifdef HAVE_IPV6
@@ -502,7 +527,7 @@ struct server *receive_query(struct listener *listen, char *packet, char *mxname
}
m = answer_request (header, ((char *) header) + PACKETSZ, (unsigned int)n,
mxname, mxtarget, options, now, local_ttl, namebuff);
mxnames, mxtarget, options, now, local_ttl, namebuff);
if (m >= 1)
send_from(listen->fd, options & OPT_NOWILD, (char *)header, m, &source_addr, &dst_addr);
else

View File

@@ -30,14 +30,17 @@ static struct irec *add_iface(struct irec *list, char *name, union mysockaddr *a
/* we may need to check the whitelist */
if (names || addrs)
{
int found = 0;
for (tmp = names; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, name) == 0))
break;
if (!tmp)
for (tmp = addrs; tmp; tmp = tmp->next)
if (sockaddr_isequal(&tmp->addr, addr))
break;
if (!tmp)
found = tmp->used = 1;
for (tmp = addrs; tmp; tmp = tmp->next)
if (sockaddr_isequal(&tmp->addr, addr))
found = tmp->used = 1;
if (!found)
return list;
}
@@ -72,7 +75,7 @@ struct irec *enumerate_interfaces(struct iname **names,
if (fd == -1)
die ("cannot create socket to enumerate interfaces: %s", NULL);
while (1)
{
buf = safe_malloc(len);
@@ -137,15 +140,24 @@ struct irec *enumerate_interfaces(struct iname **names,
die("ioctl error getting interface flags: %m", NULL);
/* If we are restricting the set of interfaces to use, make
sure that loopback interfaces are in that set. Note that
this is done as addresses rather than interface names so
as not to confuse the no-IPRECVIF workaround on the DHCP code */
sure that loopback interfaces are in that set. */
if (*names && (ifr->ifr_flags & IFF_LOOPBACK))
{
struct iname *lo = safe_malloc(sizeof(struct iname));
lo->addr = addr;
lo->next = *addrs;
*addrs = lo;
struct iname *lo;
for (lo = *names; lo; lo = lo->next)
if (lo->name && strcmp(lo->name, ifr->ifr_name) == 0)
{
lo->isloop = 1;
break;
}
if (!lo)
{
lo = safe_malloc(sizeof(struct iname));
lo->name = safe_string_alloc(ifr->ifr_name);
lo->isloop = lo->used = 1;
lo->next = *names;
*names = lo;
}
}
iface = add_iface(iface, ifr->ifr_name, &addr, *names, *addrs, except);
@@ -192,17 +204,7 @@ struct irec *enumerate_interfaces(struct iname **names,
}
if (found)
{
if (*names && (ifr->ifr_flags & IFF_LOOPBACK))
{
struct iname *lo = safe_malloc(sizeof(struct iname));
lo->addr = addr6;
lo->next = *addrs;
*addrs = lo;
}
iface = add_iface(iface, ifr->ifr_name, &addr6, *names, *addrs, except);
}
iface = add_iface(iface, ifr->ifr_name, &addr6, *names, *addrs, except);
}
#endif /* LINUX */
}
@@ -220,6 +222,9 @@ struct irec *enumerate_interfaces(struct iname **names,
struct listener *create_wildcard_listeners(int port)
{
#if !(defined(IP_PKTINFO) || (defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR)))
return NULL;
#else
union mysockaddr addr;
int opt = 1;
struct listener *listen;
@@ -235,7 +240,10 @@ struct listener *create_wildcard_listeners(int port)
#endif
listen = safe_malloc(sizeof(struct listener));
if ((listen->fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
die("failed to create socket: %s", NULL);
{
free(listen);
return NULL;
}
if (setsockopt(listen->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
#if defined(IP_PKTINFO)
setsockopt(listen->fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1 ||
@@ -244,7 +252,11 @@ struct listener *create_wildcard_listeners(int port)
setsockopt(listen->fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1 ||
#endif
bind(listen->fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
die("failed to bind socket: %s", NULL);
{
close(listen->fd);
free(listen);
return NULL;
}
listen->next = NULL;
listen->family = AF_INET;
#ifdef HAVE_IPV6
@@ -260,7 +272,11 @@ struct listener *create_wildcard_listeners(int port)
if (errno != EPROTONOSUPPORT &&
errno != EAFNOSUPPORT &&
errno != EINVAL)
die("failed to create IPv6 socket: %s", NULL);
{
close(listen->fd);
free(listen);
return NULL;
}
}
else
{
@@ -271,11 +287,19 @@ struct listener *create_wildcard_listeners(int port)
if (setsockopt(listen->next->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
setsockopt(listen->next->fd, IPV6_LEVEL, IPV6_PKTINFO, &opt, sizeof(opt)) == -1 ||
bind(listen->next->fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
die("failed to bind IPv6 socket: %s", NULL);
{
close(listen->next->fd);
free(listen->next);
close(listen->fd);
free(listen);
return NULL;
}
}
#endif
return listen;
#endif
}
struct listener *create_bound_listeners(struct irec *interfaces)
@@ -455,7 +479,7 @@ struct server *reload_servers(char *fname, char *buff, struct server *serv, int
if (!token || strcmp(token, "nameserver") != 0)
continue;
if (!(token = strtok(NULL, " \t\n")))
if (!(token = strtok(NULL, " \t\n\r")))
continue;
#ifdef HAVE_IPV6

View File

@@ -154,7 +154,7 @@ static char *usage =
unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **resolv_files,
char **mxname, char **mxtarget, char **lease_file,
struct mx_record **mxnames, char **mxtarget, char **lease_file,
char **username, char **groupname, char **domain_suffix, char **runfile,
struct iname **if_names, struct iname **if_addrs, struct iname **if_except,
struct bogus_addr **bogus_addr, struct server **serv_addrs, int *cachesize, int *port,
@@ -346,11 +346,22 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
}
case 'm':
if (!canonicalise(optarg))
option = '?';
else
*mxname = safe_string_alloc(optarg);
break;
{
char *comma = strchr(optarg, ',');
if (comma)
*(comma++) = 0;
if (!canonicalise(optarg) || (comma && !canonicalise(comma)))
option = '?';
else
{
struct mx_record *new = safe_malloc(sizeof(struct mx_record));
new->next = *mxnames;
*mxnames = new;
new->mxname = safe_string_alloc(optarg);
new->mxtarget = safe_string_alloc(comma); /* may be NULL */
}
break;
}
case 't':
if (!canonicalise(optarg))
@@ -371,7 +382,9 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
break;
case 's':
if (!canonicalise(optarg))
if (strcmp (optarg, "#") == 0)
flags |= OPT_RESOLV_DOMAIN;
else if (!canonicalise(optarg))
option = '?';
else
*domain_suffix = safe_string_alloc(optarg);
@@ -393,6 +406,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
/* new->name may be NULL if someone does
"interface=" to disable all interfaces except loop. */
new->name = safe_string_alloc(optarg);
new->isloop = new->used = 0;
if (strchr(optarg, ':'))
flags |= OPT_NOWILD;
break;
@@ -481,7 +495,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
/* # matches everything and becomes a zero length domain string */
if (strcmp(optarg, "#") == 0)
domain = "";
else if (!canonicalise(optarg))
else if (!canonicalise(optarg) && strlen(optarg) != 0)
option = '?';
else
domain = safe_string_alloc(optarg); /* NULL if strlen is zero */
@@ -1191,13 +1205,18 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
/* only one of these need be specified: the other defaults to the
host-name */
if ((flags & OPT_LOCALMX) || *mxname || *mxtarget)
if ((flags & OPT_LOCALMX) || *mxnames || *mxtarget)
{
if (gethostname(buff, MAXDNAME) == -1)
die("cannot get host-name: %s", NULL);
if (!*mxname)
*mxname = safe_string_alloc(buff);
if (!*mxnames)
{
*mxnames = safe_malloc(sizeof(struct mx_record));
(*mxnames)->next = NULL;
(*mxnames)->mxtarget = NULL;
(*mxnames)->mxname = safe_string_alloc(buff);
}
if (!*mxtarget)
*mxtarget = safe_string_alloc(buff);
@@ -1207,7 +1226,36 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
*resolv_files = 0;
else if (*resolv_files && (*resolv_files)->next && (flags & OPT_NO_POLL))
die("only one resolv.conf file allowed in no-poll mode.", NULL);
if (flags & OPT_RESOLV_DOMAIN)
{
char *line;
if (!*resolv_files || (*resolv_files)->next)
die("must have exactly one resolv.conf to read domain from.", NULL);
if (!(f = fopen((*resolv_files)->name, "r")))
die("failed to read %s: %m", (*resolv_files)->name);
while ((line = fgets(buff, MAXDNAME, f)))
{
char *token = strtok(line, " \t\n\r");
if (!token || strcmp(token, "search") != 0)
continue;
if ((token = strtok(NULL, " \t\n\r")) &&
canonicalise(token) &&
(*domain_suffix = safe_string_alloc(token)))
break;
}
fclose(f);
if (!*domain_suffix)
die("no search directive found in %s", (*resolv_files)->name);
}
return flags;
}

View File

@@ -728,7 +728,7 @@ int check_for_bogus_wildcard(HEADER *header, unsigned int qlen, char *name,
}
/* return zero if we can't answer from cache, or packet size if we can */
int answer_request(HEADER *header, char *limit, unsigned int qlen, char *mxname,
int answer_request(HEADER *header, char *limit, unsigned int qlen, struct mx_record *mxnames,
char *mxtarget, unsigned int options, time_t now,
unsigned long local_ttl, char *name)
{
@@ -988,9 +988,14 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, char *mxname,
if (qtype == T_MX || qtype == T_ANY)
{
if (mxname && hostname_isequal(name, mxname))
struct mx_record *mx;
for (mx = mxnames; mx; mx = mx->next)
if (hostname_isequal(name, mx->mxname))
break;
if (mx)
{
ansp = add_text_record(nameoffset, ansp, local_ttl, 1, T_MX, mxtarget);
ansp = add_text_record(nameoffset, ansp, local_ttl, 1, T_MX,
mx->mxtarget ? mx->mxtarget : mxtarget);
anscount++;
ans = 1;
}