mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 10:18:25 +00:00
import of dnsmasq-2.9.tar.gz
This commit is contained in:
53
CHANGELOG
53
CHANGELOG
@@ -1003,3 +1003,56 @@ release 2.8
|
||||
existing hostname, don't wipe it out.
|
||||
|
||||
Tweaked option parsing to flag some parameter errors.
|
||||
|
||||
release 2.9
|
||||
Fixed interface filter code for two effects: 1) Fixed bug
|
||||
where queries sent via loopback interface
|
||||
but to the address of another interface were ignored
|
||||
unless the loopback interface was explicitly configured.
|
||||
2) on OpenBSD failure to configure one interface now
|
||||
causes a fatal error on startup rather than an huge
|
||||
stream of log messages. Thanks to Erik Jan Tromp for
|
||||
finding that bug.
|
||||
|
||||
Changed server selection strategy to improve performance
|
||||
when there are many available servers and some are
|
||||
broken. The new algorithm is to pick as before for the
|
||||
first try, but if a query is retried, to send to all
|
||||
available servers in parallel. The first one to reply
|
||||
then becomes prefered for the next query. This should
|
||||
improve reliability without generating significant extra
|
||||
upstream load.
|
||||
|
||||
Fixed breakage of special servers/addresses for
|
||||
unqualified domains introduced in version 2.8
|
||||
|
||||
Allow fallback to "bind-interfaces" at runtime: Some
|
||||
verions of *BSD seem to have enough stuff in the header
|
||||
files to build but no kernel support. Also now log if
|
||||
"bind-interfaces" is forced on.
|
||||
|
||||
Log replies from upstream servers which refuse to do
|
||||
recursion - dnsmasq is not a recursive nameserver and
|
||||
relies on upstream servers to do the recursion, this
|
||||
flags a configuration error.
|
||||
|
||||
Disable client-id matching for hosts whose MAC address is
|
||||
read from /etc/ethers. Patch from Oleg I. Vdovikin.
|
||||
|
||||
Extended --mx-host flag to allow arbitrary targets for MX
|
||||
records, suggested by Moritz Bunkus.
|
||||
|
||||
Fixed build under NetBSD 2.0 - thanks to Felix Deichmann
|
||||
for the patch.
|
||||
|
||||
Deal correctly with repeated addresses in /etc/hosts. The
|
||||
first name found is now returned for reverse lookups,
|
||||
rather than all of them.
|
||||
|
||||
Add back fatal errors when nonexistant
|
||||
interfaces or interface addresses are given but only in
|
||||
"bind-interfaces" mode. Principle of least surprise applies.
|
||||
|
||||
Allow # as the argument to --domain, meaning "read the
|
||||
domain from the first search directive in
|
||||
/etc.resolv.conf". Feature suggested by Evan Jones.
|
||||
|
||||
55
FAQ
55
FAQ
@@ -206,19 +206,66 @@ A: What is happening is this: The boot process sends a DHCP
|
||||
the MAC address has a static allocation, that address is still in
|
||||
use by the first incarnation of the machine (the one from the boot,
|
||||
without a client ID.) dnsmasq therefore has to give the machine a
|
||||
dynamic address from its pool. There are two ways to solve this:
|
||||
dynamic address from its pool. There are three ways to solve this:
|
||||
(1) persuade your DHCP client not to send a client ID, or (2) set up
|
||||
the static assignment to the client ID, not the MAC address. The
|
||||
default client-id will be 01:<MAC address>, so change the dhcp-host
|
||||
line from "dhcp-host=11:22:33:44:55:66,1.2.3.4" to
|
||||
"dhcp-host=id:01:11:22:33:44:55:66,1.2.3.4"
|
||||
"dhcp-host=id:01:11:22:33:44:55:66,1.2.3.4" or (3) tell dnsmasq to
|
||||
ignore client IDs for a particular MAC address, like this:
|
||||
dhcp-host=11:22:33:44:55:66,id:*
|
||||
|
||||
Q: What network types are supported by the DHCP server?
|
||||
|
||||
A: Ethernet (and 802.11 wireless) are supported on all platforms. On
|
||||
Linux Token Ring is also supported.
|
||||
|
||||
|
||||
|
||||
Q: What is this strange "bind-interface" option?
|
||||
|
||||
A: The DNS spec says that the reply to a DNS query must come from the
|
||||
same address it was sent to. The traditional way to write an UDP
|
||||
server to do this is to find all of the addresses belonging to the
|
||||
machine (ie all the interfaces on the machine) and then create a
|
||||
socket for each interface which is bound to the address of the
|
||||
interface. Then when a packet is sent to address A, it is received
|
||||
on the socket bound to address A and when the reply is also sent
|
||||
via that socket, the source address is set to A by the kernel and
|
||||
everything works. This is the how dnsmasq works when
|
||||
"bind-interfaces" is set, with the obvious extension that is misses
|
||||
out creating sockets for some interfaces depending on the
|
||||
--interface, --address and --except-interface flags. The
|
||||
disadvantage of this approach is that it breaks if interfaces don't
|
||||
exist or are not configured when the daemon starts and does the
|
||||
socket creation step. In a hotplug-aware world this is a real
|
||||
problem.
|
||||
|
||||
The alternative approach is to have only one socket, which is bound
|
||||
to the correct port and the wildcard IP address (0.0.0.0). That
|
||||
socket will receive _all_ packets sent to port 53, no matter what
|
||||
destination address they have. This solves the problem of
|
||||
interfaces which are created or reconfigured after daemon
|
||||
start-up. To make this work is more complicated because of the
|
||||
"reply source address" problem. When a UDP packet is sent by a
|
||||
socket bound to 0.0.0.0 its source address will be set to the
|
||||
address of one of the machine's interfaces, but which one is not
|
||||
determined and can vary depending on the OS being run. To get round
|
||||
this it is neccessary to use a scary advanced API to determine the
|
||||
address to which a query was sent, and force that to be the source
|
||||
address in the reply. For IPv4 this stuff in non-portable and quite
|
||||
often not even available (It's different between FreeBSD 5.x and
|
||||
Linux, for instance, and FreeBSD 4.x, Linux 2.0.x and OpenBSD don't
|
||||
have it at all.) Hence "bind-interfaces" has to always be available
|
||||
as a fall back. For IPv6 the API is standard and universally
|
||||
available.
|
||||
|
||||
It could be argued that if the --interface or --address flags are
|
||||
used then binding interfaces is more appropriate, but using
|
||||
wildcard binding means that dnsmasq will quite happily start up
|
||||
after being told to use interfaces which don't exist, but which are
|
||||
created later. Wildcard binding breaks the scenario when dnsmasq is
|
||||
listening on one interface and another server (most probably BIND)
|
||||
is listening on another. It's not possible for BIND to bind to an
|
||||
(address,port) pair when dnsmasq has bound (wildcard,port), hence
|
||||
the ability to explicitly turn off wildcard binding.
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
###############################################################################
|
||||
|
||||
Name: dnsmasq
|
||||
Version: 2.8
|
||||
Version: 2.9
|
||||
Release: 1
|
||||
Copyright: GPL
|
||||
Group: System Environment/Daemons
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
###############################################################################
|
||||
|
||||
Name: dnsmasq
|
||||
Version: 2.8
|
||||
Version: 2.9
|
||||
Release: 1
|
||||
Copyright: GPL
|
||||
Group: Productivity/Networking/DNS/Servers
|
||||
|
||||
14
dnsmasq.8
14
dnsmasq.8
@@ -120,7 +120,9 @@ option forces dnsmasq to really bind only the interfaces it is
|
||||
listening on. About the only time when this is useful is when
|
||||
running another nameserver on the same machine or using IP
|
||||
alias. Specifying interfaces with IP alias automatically turns this
|
||||
option on.
|
||||
option on. Note that this only applies to the DNS part of dnsmasq, the
|
||||
DHCP server always binds the wildcard address in order to receive
|
||||
broadcast packets.
|
||||
.TP
|
||||
.B \-b, --bogus-priv
|
||||
Bogus private reverse lookups. All reverse lookups for private IP ranges (ie 192.168.x.x, etc)
|
||||
@@ -230,8 +232,10 @@ additional facility that /#/ matches any domain. Thus
|
||||
answered from /etc/hosts or DHCP and not sent to an upstream
|
||||
nameserver by a more specific --server directive.
|
||||
.TP
|
||||
.B \-m, --mx-host=<mx name>
|
||||
Return an MX record named <mx name> pointing to the host specified in the --mx-target switch
|
||||
.B \-m, --mx-host=<mx name>[,<hostname>]
|
||||
Return an MX record named <mx name> pointing to the given hostname (if
|
||||
given), or
|
||||
the host specified in the --mx-target switch
|
||||
or, if that switch is not given, the host on which dnsmasq
|
||||
is running. This is useful for directing mail from systems on a LAN
|
||||
to a central server.
|
||||
@@ -409,7 +413,9 @@ for DHCP-configured hosts to claim. The intention is to constrain hostnames so t
|
||||
.B --domain-suffix=thekelleys.org.uk
|
||||
and have a machine whose DHCP hostname is "laptop". The IP address for that machine is available from
|
||||
.B dnsmasq
|
||||
both as "laptop" and "laptop.thekelleys.org.uk".
|
||||
both as "laptop" and "laptop.thekelleys.org.uk". If the domain is
|
||||
given as "#" then the domain is read from the first "search" directive
|
||||
in /etc/resolv.conf (or equivalent).
|
||||
.TP
|
||||
.B \-E, --expand-hosts
|
||||
Add the domain-suffix to simple names (without a period) in /etc/hosts
|
||||
|
||||
7
doc.html
7
doc.html
@@ -18,8 +18,9 @@ connected to the internet via a modem, cable-modem or ADSL
|
||||
connection but would be a good choice for any small network where low
|
||||
resource use and ease of configuration are important.
|
||||
<P>
|
||||
Dnsmasq is included in at least the following Linux distributions: Gentoo, Debian,
|
||||
Smoothwall, IP-Cop, floppyfw, Firebox, Freesco and
|
||||
Dnsmasq is included in at least the following Linux distributions:
|
||||
Gentoo, Debian, Slackware, Suse,
|
||||
Smoothwall, IP-Cop, floppyfw, Firebox, Freesco, CoyoteLinux and
|
||||
Clarkconnect. It is also available as a FreeBSD port and is used in Linksys wireless routers.
|
||||
<P>
|
||||
Dnsmasq provides the following features:
|
||||
@@ -86,7 +87,7 @@ in the .com and .net TLDs
|
||||
|
||||
<H2>Download.</H2>
|
||||
|
||||
Download dnsmasq <A HREF="http://www.thekelleys.org.uk/dnsmasq/"> here</A>.
|
||||
<A HREF="http://www.thekelleys.org.uk/dnsmasq/"> Download</A> dnsmasq here.
|
||||
The tarball includes this documentation, source, manpage and control files for building .rpms.
|
||||
There are also pre-built i386 .rpms, and a
|
||||
<A HREF="CHANGELOG"> CHANGELOG</A>.
|
||||
|
||||
21
src/cache.c
21
src/cache.c
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
13
src/config.h
13
src/config.h
@@ -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 */
|
||||
|
||||
12
src/dhcp.c
12
src/dhcp.c
@@ -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++;
|
||||
|
||||
@@ -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,17 +125,40 @@ 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_wildcard_listeners(port)))
|
||||
{
|
||||
bind_fallback = 1;
|
||||
options |= OPT_NOWILD;
|
||||
}
|
||||
|
||||
if (options & OPT_NOWILD)
|
||||
listeners = create_bound_listeners(interfaces);
|
||||
else
|
||||
listeners = create_wildcard_listeners(port);
|
||||
{
|
||||
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,11 +261,8 @@ 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)
|
||||
{
|
||||
@@ -256,7 +286,8 @@ 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)
|
||||
{
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
235
src/forward.c
235
src/forward.c
@@ -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,9 +223,12 @@ 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;
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
70
src/option.c
70
src/option.c
@@ -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);
|
||||
@@ -1208,6 +1227,35 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user