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.
|
existing hostname, don't wipe it out.
|
||||||
|
|
||||||
Tweaked option parsing to flag some parameter errors.
|
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
|
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,
|
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
|
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
|
(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
|
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
|
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
|
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?
|
Q: What network types are supported by the DHCP server?
|
||||||
|
|
||||||
A: Ethernet (and 802.11 wireless) are supported on all platforms. On
|
A: Ethernet (and 802.11 wireless) are supported on all platforms. On
|
||||||
Linux Token Ring is also supported.
|
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
|
Name: dnsmasq
|
||||||
Version: 2.8
|
Version: 2.9
|
||||||
Release: 1
|
Release: 1
|
||||||
Copyright: GPL
|
Copyright: GPL
|
||||||
Group: System Environment/Daemons
|
Group: System Environment/Daemons
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
Name: dnsmasq
|
Name: dnsmasq
|
||||||
Version: 2.8
|
Version: 2.9
|
||||||
Release: 1
|
Release: 1
|
||||||
Copyright: GPL
|
Copyright: GPL
|
||||||
Group: Productivity/Networking/DNS/Servers
|
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
|
listening on. About the only time when this is useful is when
|
||||||
running another nameserver on the same machine or using IP
|
running another nameserver on the same machine or using IP
|
||||||
alias. Specifying interfaces with IP alias automatically turns this
|
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
|
.TP
|
||||||
.B \-b, --bogus-priv
|
.B \-b, --bogus-priv
|
||||||
Bogus private reverse lookups. All reverse lookups for private IP ranges (ie 192.168.x.x, etc)
|
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
|
answered from /etc/hosts or DHCP and not sent to an upstream
|
||||||
nameserver by a more specific --server directive.
|
nameserver by a more specific --server directive.
|
||||||
.TP
|
.TP
|
||||||
.B \-m, --mx-host=<mx name>
|
.B \-m, --mx-host=<mx name>[,<hostname>]
|
||||||
Return an MX record named <mx name> pointing to the host specified in the --mx-target switch
|
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
|
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
|
is running. This is useful for directing mail from systems on a LAN
|
||||||
to a central server.
|
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
|
.B --domain-suffix=thekelleys.org.uk
|
||||||
and have a machine whose DHCP hostname is "laptop". The IP address for that machine is available from
|
and have a machine whose DHCP hostname is "laptop". The IP address for that machine is available from
|
||||||
.B dnsmasq
|
.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
|
.TP
|
||||||
.B \-E, --expand-hosts
|
.B \-E, --expand-hosts
|
||||||
Add the domain-suffix to simple names (without a period) in /etc/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
|
connection but would be a good choice for any small network where low
|
||||||
resource use and ease of configuration are important.
|
resource use and ease of configuration are important.
|
||||||
<P>
|
<P>
|
||||||
Dnsmasq is included in at least the following Linux distributions: Gentoo, Debian,
|
Dnsmasq is included in at least the following Linux distributions:
|
||||||
Smoothwall, IP-Cop, floppyfw, Firebox, Freesco and
|
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.
|
Clarkconnect. It is also available as a FreeBSD port and is used in Linksys wireless routers.
|
||||||
<P>
|
<P>
|
||||||
Dnsmasq provides the following features:
|
Dnsmasq provides the following features:
|
||||||
@@ -86,7 +87,7 @@ in the .com and .net TLDs
|
|||||||
|
|
||||||
<H2>Download.</H2>
|
<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.
|
The tarball includes this documentation, source, manpage and control files for building .rpms.
|
||||||
There are also pre-built i386 .rpms, and a
|
There are also pre-built i386 .rpms, and a
|
||||||
<A HREF="CHANGELOG"> CHANGELOG</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));
|
struct crec *lookup = cache_find_by_name(NULL, cache->name.sname, 0, flags & (F_IPV4 | F_IPV6));
|
||||||
|
|
||||||
/* Remove duplicates in hosts files. */
|
/* Remove duplicates in hosts files. */
|
||||||
if (lookup && (lookup->flags & F_HOSTS) &&
|
if (lookup && (lookup->flags & F_HOSTS) &&
|
||||||
memcmp(&lookup->addr, addr, addrlen) == 0)
|
memcmp(&lookup->addr, addr, addrlen) == 0)
|
||||||
free(cache);
|
free(cache);
|
||||||
else
|
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;
|
cache->flags = flags;
|
||||||
memcpy(&cache->addr, addr, addrlen);
|
memcpy(&cache->addr, addr, addrlen);
|
||||||
cache_hash(cache);
|
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");
|
FILE *f = fopen(filename, "r");
|
||||||
char *line;
|
char *line;
|
||||||
@@ -529,6 +531,9 @@ static void read_hostsfile(char *filename, int opts, char *buff, char *domain_su
|
|||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (is_addn)
|
||||||
|
flags |= F_ADDN;
|
||||||
|
|
||||||
while ((token = strtok(NULL, " \t\n\r")) && (*token != '#'))
|
while ((token = strtok(NULL, " \t\n\r")) && (*token != '#'))
|
||||||
{
|
{
|
||||||
struct crec *cache;
|
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);
|
strcpy(cache->name.sname, token);
|
||||||
strcat(cache->name.sname, ".");
|
strcat(cache->name.sname, ".");
|
||||||
strcat(cache->name.sname, domain_suffix);
|
strcat(cache->name.sname, domain_suffix);
|
||||||
add_hosts_entry(cache, &addr, addrlen, flags | addn_flag);
|
add_hosts_entry(cache, &addr, addrlen, flags);
|
||||||
/* Only first name is cannonical and used for reverse lookups */
|
|
||||||
flags &= ~F_REVERSE;
|
|
||||||
}
|
}
|
||||||
if ((cache = malloc(sizeof(struct crec) + strlen(token)+1-SMALLDNAME)))
|
if ((cache = malloc(sizeof(struct crec) + strlen(token)+1-SMALLDNAME)))
|
||||||
{
|
{
|
||||||
strcpy(cache->name.sname, token);
|
strcpy(cache->name.sname, token);
|
||||||
add_hosts_entry(cache, &addr, addrlen, flags | addn_flag);
|
add_hosts_entry(cache, &addr, addrlen, flags);
|
||||||
/* Clear this here in case not done above. */
|
|
||||||
flags &= ~F_REVERSE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
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);
|
read_hostsfile(HOSTSFILE, opts, buff, domain_suffix, 0);
|
||||||
if (addn_hosts)
|
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;
|
addn_file = addn_hosts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
13
src/config.h
13
src/config.h
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
/* Author's email: simon@thekelleys.org.uk */
|
/* Author's email: simon@thekelleys.org.uk */
|
||||||
|
|
||||||
#define VERSION "2.8"
|
#define VERSION "2.9"
|
||||||
|
|
||||||
#define FTABSIZ 150 /* max number of outstanding requests */
|
#define FTABSIZ 150 /* max number of outstanding requests */
|
||||||
#define TIMEOUT 20 /* drop queries after TIMEOUT seconds */
|
#define TIMEOUT 20 /* drop queries after TIMEOUT seconds */
|
||||||
@@ -59,17 +59,6 @@
|
|||||||
#endif
|
#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 */
|
/* Decide if we're going to support IPv6 */
|
||||||
/* We assume that systems which don't have IPv6
|
/* We assume that systems which don't have IPv6
|
||||||
headers don't have ntop and pton either */
|
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;
|
return;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
if (!names || !names->name || names->next)
|
while (names->isloop)
|
||||||
{
|
names = names->next;
|
||||||
syslog(LOG_ERR, "must set exactly one interface on broken systems without IP_RECVIF");
|
strcpy(ifr.ifr_name, names->name);
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
strcpy(ifr.ifr_name, names->name);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_BPF
|
#ifdef HAVE_BPF
|
||||||
@@ -572,7 +568,7 @@ struct dhcp_config *dhcp_read_ethers(struct dhcp_config *configs, char *buff)
|
|||||||
config->addr = addr;
|
config->addr = addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
config->flags |= CONFIG_HWADDR;
|
config->flags |= CONFIG_HWADDR | CONFIG_NOCLID;
|
||||||
memcpy(config->hwaddr, hwaddr, ETHER_ADDR_LEN);
|
memcpy(config->hwaddr, hwaddr, ETHER_ADDR_LEN);
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
|
|||||||
@@ -37,15 +37,16 @@ int main (int argc, char **argv)
|
|||||||
int maxleases = MAXLEASES;
|
int maxleases = MAXLEASES;
|
||||||
int query_port = 0;
|
int query_port = 0;
|
||||||
int first_loop = 1;
|
int first_loop = 1;
|
||||||
|
int bind_fallback = 0;
|
||||||
unsigned long local_ttl = 0;
|
unsigned long local_ttl = 0;
|
||||||
unsigned int options, min_leasetime;
|
unsigned int options, min_leasetime;
|
||||||
char *runfile = RUNFILE;
|
char *runfile = RUNFILE;
|
||||||
time_t resolv_changed = 0;
|
time_t resolv_changed = 0;
|
||||||
time_t now, last = 0;
|
time_t now, last = 0;
|
||||||
struct irec *interfaces = NULL;
|
struct irec *interfaces = NULL;
|
||||||
struct listener *listener, *listeners;
|
struct listener *listener, *listeners = NULL;
|
||||||
struct doctor *doctors = NULL;
|
struct doctor *doctors = NULL;
|
||||||
char *mxname = NULL;
|
struct mx_record *mxnames = NULL;
|
||||||
char *mxtarget = NULL;
|
char *mxtarget = NULL;
|
||||||
char *lease_file = NULL;
|
char *lease_file = NULL;
|
||||||
char *addn_hosts = NULL;
|
char *addn_hosts = NULL;
|
||||||
@@ -106,7 +107,7 @@ int main (int argc, char **argv)
|
|||||||
packet = safe_malloc(DNSMASQ_PACKETSZ);
|
packet = safe_malloc(DNSMASQ_PACKETSZ);
|
||||||
|
|
||||||
dhcp_next_server.s_addr = 0;
|
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,
|
&username, &groupname, &domain_suffix, &runfile,
|
||||||
&if_names, &if_addrs, &if_except, &bogus_addr,
|
&if_names, &if_addrs, &if_except, &bogus_addr,
|
||||||
&serv_addrs, &cachesize, &port, &query_port, &local_ttl, &addn_hosts,
|
&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);
|
die("ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h", NULL);
|
||||||
#endif
|
#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);
|
interfaces = enumerate_interfaces(&if_names, &if_addrs, if_except, port);
|
||||||
if (options & OPT_NOWILD)
|
|
||||||
listeners = create_bound_listeners(interfaces);
|
if (!(options & OPT_NOWILD) && !(listeners = create_wildcard_listeners(port)))
|
||||||
else
|
{
|
||||||
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);
|
forward_init(1);
|
||||||
cache_init(cachesize, options & OPT_LOG);
|
cache_init(cachesize, options & OPT_LOG);
|
||||||
|
|
||||||
@@ -148,6 +172,15 @@ int main (int argc, char **argv)
|
|||||||
|
|
||||||
if (dhcp)
|
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);
|
dhcp_init(&dhcpfd, &dhcp_raw_fd);
|
||||||
leasefd = lease_init(lease_file, domain_suffix, dnamebuff, packet, now, maxleases);
|
leasefd = lease_init(lease_file, domain_suffix, dnamebuff, packet, now, maxleases);
|
||||||
}
|
}
|
||||||
@@ -228,12 +261,9 @@ int main (int argc, char **argv)
|
|||||||
else
|
else
|
||||||
syslog(LOG_INFO, "started, version %s cache disabled", VERSION);
|
syslog(LOG_INFO, "started, version %s cache disabled", VERSION);
|
||||||
|
|
||||||
if (options & OPT_LOCALMX)
|
if (bind_fallback)
|
||||||
syslog(LOG_INFO, "serving MX record for local hosts target %s", mxtarget);
|
syslog(LOG_WARNING, "setting --bind-interfaces option because if OS limitations");
|
||||||
else if (mxname)
|
|
||||||
syslog(LOG_INFO, "serving MX record for mailhost %s target %s",
|
|
||||||
mxname, mxtarget);
|
|
||||||
|
|
||||||
for (dhcp_tmp = dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
|
for (dhcp_tmp = dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
|
||||||
{
|
{
|
||||||
strcpy(dnamebuff, inet_ntoa(dhcp_tmp->start));
|
strcpy(dnamebuff, inet_ntoa(dhcp_tmp->start));
|
||||||
@@ -256,8 +286,9 @@ int main (int argc, char **argv)
|
|||||||
if (getuid() == 0 || geteuid() == 0)
|
if (getuid() == 0 || geteuid() == 0)
|
||||||
syslog(LOG_WARNING, "failed to drop root privs");
|
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)
|
while (sigterm == 0)
|
||||||
{
|
{
|
||||||
fd_set rset;
|
fd_set rset;
|
||||||
@@ -275,9 +306,11 @@ int main (int argc, char **argv)
|
|||||||
lease_update_dns();
|
lease_update_dns();
|
||||||
}
|
}
|
||||||
if (resolv && (options & OPT_NO_POLL))
|
if (resolv && (options & OPT_NO_POLL))
|
||||||
servers = last_server =
|
{
|
||||||
check_servers(reload_servers(resolv->name, dnamebuff, servers, query_port),
|
servers = check_servers(reload_servers(resolv->name, dnamebuff, servers, query_port),
|
||||||
interfaces, &sfds);
|
interfaces, &sfds);
|
||||||
|
last_server = NULL;
|
||||||
|
}
|
||||||
sighup = 0;
|
sighup = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,7 +406,7 @@ int main (int argc, char **argv)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
res->logged = 0;
|
res->logged = 0;
|
||||||
if (statbuf.st_mtime > last_change)
|
if (difftime(statbuf.st_mtime, last_change) > 0.0)
|
||||||
{
|
{
|
||||||
last_change = statbuf.st_mtime;
|
last_change = statbuf.st_mtime;
|
||||||
latest = res;
|
latest = res;
|
||||||
@@ -382,20 +415,20 @@ int main (int argc, char **argv)
|
|||||||
res = res->next;
|
res = res->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (latest && last_change > resolv_changed)
|
if (latest && difftime(last_change, resolv_changed) > 0.0)
|
||||||
{
|
{
|
||||||
resolv_changed = last_change;
|
resolv_changed = last_change;
|
||||||
servers = last_server =
|
servers = check_servers(reload_servers(latest->name, dnamebuff, servers, query_port),
|
||||||
check_servers(reload_servers(latest->name, dnamebuff, servers, query_port),
|
interfaces, &sfds);
|
||||||
interfaces, &sfds);
|
last_server = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (serverfdp = sfds; serverfdp; serverfdp = serverfdp->next)
|
for (serverfdp = sfds; serverfdp; serverfdp = serverfdp->next)
|
||||||
if (FD_ISSET(serverfdp->fd, &rset))
|
if (FD_ISSET(serverfdp->fd, &rset))
|
||||||
last_server = reply_query(serverfdp->fd, options, packet, now,
|
last_server = reply_query(serverfdp, options, packet, now,
|
||||||
dnamebuff, last_server, bogus_addr, doctors);
|
dnamebuff, servers, last_server, bogus_addr, doctors);
|
||||||
|
|
||||||
if (dhcp && FD_ISSET(dhcpfd, &rset))
|
if (dhcp && FD_ISSET(dhcpfd, &rset))
|
||||||
dhcp_packet(dhcp, packet, dhcp_options, dhcp_configs, dhcp_vendors,
|
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)
|
for (listener = listeners; listener; listener = listener->next)
|
||||||
if (FD_ISSET(listener->fd, &rset))
|
if (FD_ISSET(listener->fd, &rset))
|
||||||
last_server = receive_query(listener, packet,
|
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);
|
if_names, if_addrs, if_except, last_server, servers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#if defined(__OpenBSD__)
|
#if defined(__OpenBSD__) || defined(__NetBSD__)
|
||||||
# include <netinet/if_ether.h>
|
# include <netinet/if_ether.h>
|
||||||
#else
|
#else
|
||||||
# include <net/ethernet.h>
|
# include <net/ethernet.h>
|
||||||
@@ -91,6 +91,7 @@
|
|||||||
#define OPT_NODOTS_LOCAL 4096
|
#define OPT_NODOTS_LOCAL 4096
|
||||||
#define OPT_NOWILD 8192
|
#define OPT_NOWILD 8192
|
||||||
#define OPT_ETHERS 16384
|
#define OPT_ETHERS 16384
|
||||||
|
#define OPT_RESOLV_DOMAIN 32768
|
||||||
|
|
||||||
struct all_addr {
|
struct all_addr {
|
||||||
union {
|
union {
|
||||||
@@ -112,6 +113,11 @@ struct doctor {
|
|||||||
struct doctor *next;
|
struct doctor *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mx_record {
|
||||||
|
char *mxname, *mxtarget;
|
||||||
|
struct mx_record *next;
|
||||||
|
};
|
||||||
|
|
||||||
union bigname {
|
union bigname {
|
||||||
char name[MAXDNAME];
|
char name[MAXDNAME];
|
||||||
union bigname *next; /* freelist */
|
union bigname *next; /* freelist */
|
||||||
@@ -206,6 +212,7 @@ struct listener {
|
|||||||
struct iname {
|
struct iname {
|
||||||
char *name;
|
char *name;
|
||||||
union mysockaddr addr;
|
union mysockaddr addr;
|
||||||
|
int isloop, used;
|
||||||
struct iname *next;
|
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,
|
void extract_addresses(HEADER *header, unsigned int qlen, char *namebuff,
|
||||||
time_t now, struct doctor *doctors);
|
time_t now, struct doctor *doctors);
|
||||||
void extract_neg_addrs(HEADER *header, unsigned int qlen, char *namebuff, time_t now);
|
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 *mxtarget, unsigned int options, time_t now, unsigned long local_ttl,
|
||||||
char *namebuff);
|
char *namebuff);
|
||||||
int check_for_bogus_wildcard(HEADER *header, unsigned int qlen, char *name,
|
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 */
|
/* option.c */
|
||||||
unsigned int read_opts(int argc, char **argv, char *buff, struct resolvc **resolv_file,
|
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 **username, char **groupname,
|
||||||
char **domain_suffix, char **runfile,
|
char **domain_suffix, char **runfile,
|
||||||
struct iname **if_names, struct iname **if_addrs, struct iname **if_except,
|
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 */
|
/* forward.c */
|
||||||
void forward_init(int first);
|
void forward_init(int first);
|
||||||
struct server *reply_query(int fd, int options, char *packet, time_t now,
|
struct server *reply_query(struct serverfd *sfd, int options, char *packet, time_t now,
|
||||||
char *dnamebuff, struct server *last_server,
|
char *dnamebuff, struct server *servers, struct server *last_server,
|
||||||
struct bogus_addr *bogus_nxdomain, struct doctor *doctors);
|
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,
|
char *mxtarget, unsigned int options, time_t now,
|
||||||
unsigned long local_ttl, char *namebuff,
|
unsigned long local_ttl, char *namebuff,
|
||||||
struct iname *names, struct iname *addrs, struct iname *except,
|
struct iname *names, struct iname *addrs, struct iname *except,
|
||||||
|
|||||||
245
src/forward.c
245
src/forward.c
@@ -120,22 +120,27 @@ static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
{
|
{
|
||||||
struct frec *forward;
|
struct frec *forward;
|
||||||
char *domain = NULL;
|
char *domain = NULL;
|
||||||
int type = 0;
|
int forwardall = 0, type = 0;
|
||||||
struct server *serv;
|
|
||||||
struct all_addr *addrp = NULL;
|
struct all_addr *addrp = NULL;
|
||||||
unsigned short flags = 0;
|
unsigned short flags = 0;
|
||||||
unsigned short gotname = extract_request(header, (unsigned int)plen, dnamebuff);
|
unsigned short gotname = extract_request(header, (unsigned int)plen, dnamebuff);
|
||||||
|
struct server *start = NULL;
|
||||||
|
|
||||||
/* may be recursion not speced or no servers available. */
|
/* may be recursion not speced or no servers available. */
|
||||||
if (!header->rd || !servers)
|
if (!header->rd || !servers)
|
||||||
forward = NULL;
|
forward = NULL;
|
||||||
else if ((forward = lookup_frec_by_sender(ntohs(header->id), udpaddr)))
|
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;
|
domain = forward->sentto->domain;
|
||||||
|
if (!(options & OPT_ORDER))
|
||||||
|
{
|
||||||
|
forwardall = 1;
|
||||||
|
last_server = NULL;
|
||||||
|
}
|
||||||
type = forward->sentto->flags & SERV_TYPE;
|
type = forward->sentto->flags & SERV_TYPE;
|
||||||
if (!(forward->sentto = forward->sentto->next))
|
if (!(start = forward->sentto->next))
|
||||||
forward->sentto = servers; /* at end of list, recycle */
|
start = servers; /* at end of list, recycle */
|
||||||
header->id = htons(forward->new_id);
|
header->id = htons(forward->new_id);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -148,29 +153,25 @@ static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
|
|
||||||
unsigned int namelen = strlen(dnamebuff);
|
unsigned int namelen = strlen(dnamebuff);
|
||||||
unsigned int matchlen = 0;
|
unsigned int matchlen = 0;
|
||||||
|
struct server *serv;
|
||||||
|
|
||||||
for (serv=servers; serv; serv=serv->next)
|
for (serv=servers; serv; serv=serv->next)
|
||||||
/* domain matches take priority over NODOTS matches */
|
/* domain matches take priority over NODOTS matches */
|
||||||
if ((serv->flags & SERV_FOR_NODOTS) && type != SERV_HAS_DOMAIN && !strchr(dnamebuff, '.'))
|
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 */
|
flags = sflag;
|
||||||
unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
|
if (serv->addr.sa.sa_family == AF_INET)
|
||||||
if (sflag & gotname) /* only OK if addrfamily == query */
|
addrp = (struct all_addr *)&serv->addr.in.sin_addr;
|
||||||
{
|
|
||||||
type = SERV_FOR_NODOTS;
|
|
||||||
flags = sflag;
|
|
||||||
if (serv->addr.sa.sa_family == AF_INET)
|
|
||||||
addrp = (struct all_addr *)&serv->addr.in.sin_addr;
|
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else
|
else
|
||||||
addrp = (struct all_addr *)&serv->addr.in6.sin6_addr;
|
addrp = (struct all_addr *)&serv->addr.in6.sin6_addr;
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
flags = 0;
|
|
||||||
}
|
}
|
||||||
else if (serv->flags & SERV_HAS_DOMAIN)
|
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) &&
|
hostname_isequal(dnamebuff + namelen - domainlen, serv->domain) &&
|
||||||
domainlen >= matchlen)
|
domainlen >= matchlen)
|
||||||
{
|
{
|
||||||
if (serv->flags & SERV_LITERAL_ADDRESS)
|
unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
|
||||||
{ /* flags gets set if server is in fact an answer */
|
type = SERV_HAS_DOMAIN;
|
||||||
unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
|
domain = serv->domain;
|
||||||
if ((sflag | F_QUERY ) & gotname) /* only OK if addrfamily == query */
|
matchlen = domainlen;
|
||||||
{
|
flags = 0;
|
||||||
type = SERV_HAS_DOMAIN;
|
if ((serv->flags & SERV_LITERAL_ADDRESS) && ((sflag | F_QUERY ) & gotname))
|
||||||
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
|
|
||||||
{
|
{
|
||||||
flags = 0; /* may be better match from previous literal */
|
flags = gotname;
|
||||||
domain = serv->domain;
|
if (serv->addr.sa.sa_family == AF_INET)
|
||||||
matchlen = domainlen;
|
addrp = (struct all_addr *)&serv->addr.in.sin_addr;
|
||||||
type = SERV_HAS_DOMAIN;
|
#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. */
|
otherwise, use the one last known to work. */
|
||||||
|
|
||||||
if (type != 0 || (options & OPT_ORDER))
|
if (type != 0 || (options & OPT_ORDER))
|
||||||
forward->sentto = servers;
|
start = servers;
|
||||||
else
|
else if (!(start = last_server))
|
||||||
forward->sentto = last_server;
|
{
|
||||||
|
start = servers;
|
||||||
|
forwardall = 1;
|
||||||
|
}
|
||||||
|
|
||||||
forward->source = *udpaddr;
|
forward->source = *udpaddr;
|
||||||
forward->dest = *dst_addr;
|
forward->dest = *dst_addr;
|
||||||
forward->new_id = get_id();
|
forward->new_id = get_id();
|
||||||
@@ -250,52 +245,52 @@ static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
|
|
||||||
if (!flags && forward)
|
if (!flags && forward)
|
||||||
{
|
{
|
||||||
struct server *firstsentto = forward->sentto;
|
struct server *firstsentto = start;
|
||||||
|
int forwarded = 0;
|
||||||
|
|
||||||
while (1)
|
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.
|
/* only send to servers dealing with our domain.
|
||||||
domain may be NULL, in which case server->domain
|
domain may be NULL, in which case server->domain
|
||||||
must be NULL also. */
|
must be NULL also. */
|
||||||
|
|
||||||
if (type == (forward->sentto->flags & SERV_TYPE) &&
|
if (type == (start->flags & SERV_TYPE) &&
|
||||||
(type != SERV_HAS_DOMAIN || hostname_isequal(domain, forward->sentto->domain)))
|
(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. */
|
flags = F_NOERR; /* NULL servers are OK. */
|
||||||
else if (!(forward->sentto->flags & SERV_LITERAL_ADDRESS) &&
|
else if (!(start->flags & SERV_LITERAL_ADDRESS) &&
|
||||||
sendto(forward->sentto->sfd->fd, (char *)header, plen, 0,
|
sendto(start->sfd->fd, (char *)header, plen, 0,
|
||||||
&forward->sentto->addr.sa,
|
&start->addr.sa,
|
||||||
sa_len(&forward->sentto->addr)) != -1)
|
sa_len(&start->addr)) != -1)
|
||||||
{
|
{
|
||||||
log_query(logflags, gotname ? dnamebuff : "query", addrp);
|
if (!gotname)
|
||||||
/* for no-domain, don't update last_server */
|
strcpy(dnamebuff, "query");
|
||||||
return domain ? last_server : (forward->sentto->next ? forward->sentto->next : servers);
|
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))
|
if (!(start = start->next))
|
||||||
forward->sentto = servers;
|
start = servers;
|
||||||
|
|
||||||
/* check if we tried all without success */
|
if (start == firstsentto)
|
||||||
if (forward->sentto == firstsentto)
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (forwarded)
|
||||||
|
return last_server;
|
||||||
|
|
||||||
/* could not send on, prepare to return */
|
/* could not send on, prepare to return */
|
||||||
header->id = htons(forward->orig_id);
|
header->id = htons(forward->orig_id);
|
||||||
forward->new_id = 0; /* cancel */
|
forward->new_id = 0; /* cancel */
|
||||||
@@ -312,52 +307,81 @@ static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* returns new last_server */
|
/* returns new last_server */
|
||||||
struct server *reply_query(int fd, int options, char *packet, time_t now,
|
struct server *reply_query(struct serverfd *sfd, int options, char *packet, time_t now,
|
||||||
char *dnamebuff, struct server *last_server,
|
char *dnamebuff, struct server *servers, struct server *last_server,
|
||||||
struct bogus_addr *bogus_nxdomain, struct doctor *doctors)
|
struct bogus_addr *bogus_nxdomain, struct doctor *doctors)
|
||||||
{
|
{
|
||||||
/* packet from peer server, extract data for cache, and send to
|
/* packet from peer server, extract data for cache, and send to
|
||||||
original requester */
|
original requester */
|
||||||
struct frec *forward;
|
struct frec *forward;
|
||||||
HEADER *header;
|
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;
|
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)
|
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)) &&
|
||||||
if (!forward->sentto->domain)
|
sockaddr_isequal(&last_server->addr, &serveraddr))
|
||||||
last_server = forward->sentto; /* known good */
|
break;
|
||||||
if (header->opcode == QUERY)
|
if (!last_server)
|
||||||
{
|
last_server = forward->sentto;
|
||||||
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 */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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;
|
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,
|
char *mxtarget, unsigned int options, time_t now,
|
||||||
unsigned long local_ttl, char *namebuff,
|
unsigned long local_ttl, char *namebuff,
|
||||||
struct iname *names, struct iname *addrs, struct iname *except,
|
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_iov = iov;
|
||||||
msg.msg_iovlen = 1;
|
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;
|
source_addr.sa.sa_family = listen->family;
|
||||||
#ifdef HAVE_IPV6
|
#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,
|
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)
|
if (m >= 1)
|
||||||
send_from(listen->fd, options & OPT_NOWILD, (char *)header, m, &source_addr, &dst_addr);
|
send_from(listen->fd, options & OPT_NOWILD, (char *)header, m, &source_addr, &dst_addr);
|
||||||
else
|
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 */
|
/* we may need to check the whitelist */
|
||||||
if (names || addrs)
|
if (names || addrs)
|
||||||
{
|
{
|
||||||
|
int found = 0;
|
||||||
|
|
||||||
for (tmp = names; tmp; tmp = tmp->next)
|
for (tmp = names; tmp; tmp = tmp->next)
|
||||||
if (tmp->name && (strcmp(tmp->name, name) == 0))
|
if (tmp->name && (strcmp(tmp->name, name) == 0))
|
||||||
break;
|
found = tmp->used = 1;
|
||||||
if (!tmp)
|
|
||||||
for (tmp = addrs; tmp; tmp = tmp->next)
|
for (tmp = addrs; tmp; tmp = tmp->next)
|
||||||
if (sockaddr_isequal(&tmp->addr, addr))
|
if (sockaddr_isequal(&tmp->addr, addr))
|
||||||
break;
|
found = tmp->used = 1;
|
||||||
if (!tmp)
|
|
||||||
|
if (!found)
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +75,7 @@ struct irec *enumerate_interfaces(struct iname **names,
|
|||||||
|
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
die ("cannot create socket to enumerate interfaces: %s", NULL);
|
die ("cannot create socket to enumerate interfaces: %s", NULL);
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
buf = safe_malloc(len);
|
buf = safe_malloc(len);
|
||||||
@@ -137,15 +140,24 @@ struct irec *enumerate_interfaces(struct iname **names,
|
|||||||
die("ioctl error getting interface flags: %m", NULL);
|
die("ioctl error getting interface flags: %m", NULL);
|
||||||
|
|
||||||
/* If we are restricting the set of interfaces to use, make
|
/* If we are restricting the set of interfaces to use, make
|
||||||
sure that loopback interfaces are in that set. Note that
|
sure that loopback interfaces are in that set. */
|
||||||
this is done as addresses rather than interface names so
|
|
||||||
as not to confuse the no-IPRECVIF workaround on the DHCP code */
|
|
||||||
if (*names && (ifr->ifr_flags & IFF_LOOPBACK))
|
if (*names && (ifr->ifr_flags & IFF_LOOPBACK))
|
||||||
{
|
{
|
||||||
struct iname *lo = safe_malloc(sizeof(struct iname));
|
struct iname *lo;
|
||||||
lo->addr = addr;
|
for (lo = *names; lo; lo = lo->next)
|
||||||
lo->next = *addrs;
|
if (lo->name && strcmp(lo->name, ifr->ifr_name) == 0)
|
||||||
*addrs = lo;
|
{
|
||||||
|
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);
|
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 (found)
|
||||||
{
|
iface = add_iface(iface, ifr->ifr_name, &addr6, *names, *addrs, except);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif /* LINUX */
|
#endif /* LINUX */
|
||||||
}
|
}
|
||||||
@@ -220,6 +222,9 @@ struct irec *enumerate_interfaces(struct iname **names,
|
|||||||
|
|
||||||
struct listener *create_wildcard_listeners(int port)
|
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;
|
union mysockaddr addr;
|
||||||
int opt = 1;
|
int opt = 1;
|
||||||
struct listener *listen;
|
struct listener *listen;
|
||||||
@@ -235,7 +240,10 @@ struct listener *create_wildcard_listeners(int port)
|
|||||||
#endif
|
#endif
|
||||||
listen = safe_malloc(sizeof(struct listener));
|
listen = safe_malloc(sizeof(struct listener));
|
||||||
if ((listen->fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
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 (setsockopt(listen->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||||
#if defined(IP_PKTINFO)
|
#if defined(IP_PKTINFO)
|
||||||
setsockopt(listen->fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1 ||
|
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 ||
|
setsockopt(listen->fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1 ||
|
||||||
#endif
|
#endif
|
||||||
bind(listen->fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
|
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->next = NULL;
|
||||||
listen->family = AF_INET;
|
listen->family = AF_INET;
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
@@ -260,7 +272,11 @@ struct listener *create_wildcard_listeners(int port)
|
|||||||
if (errno != EPROTONOSUPPORT &&
|
if (errno != EPROTONOSUPPORT &&
|
||||||
errno != EAFNOSUPPORT &&
|
errno != EAFNOSUPPORT &&
|
||||||
errno != EINVAL)
|
errno != EINVAL)
|
||||||
die("failed to create IPv6 socket: %s", NULL);
|
{
|
||||||
|
close(listen->fd);
|
||||||
|
free(listen);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
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 ||
|
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 ||
|
setsockopt(listen->next->fd, IPV6_LEVEL, IPV6_PKTINFO, &opt, sizeof(opt)) == -1 ||
|
||||||
bind(listen->next->fd, (struct sockaddr *)&addr, sa_len(&addr)) == -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
|
#endif
|
||||||
|
|
||||||
return listen;
|
return listen;
|
||||||
|
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
struct listener *create_bound_listeners(struct irec *interfaces)
|
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)
|
if (!token || strcmp(token, "nameserver") != 0)
|
||||||
continue;
|
continue;
|
||||||
if (!(token = strtok(NULL, " \t\n")))
|
if (!(token = strtok(NULL, " \t\n\r")))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
#ifdef HAVE_IPV6
|
#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,
|
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,
|
char **username, char **groupname, char **domain_suffix, char **runfile,
|
||||||
struct iname **if_names, struct iname **if_addrs, struct iname **if_except,
|
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,
|
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':
|
case 'm':
|
||||||
if (!canonicalise(optarg))
|
{
|
||||||
option = '?';
|
char *comma = strchr(optarg, ',');
|
||||||
else
|
if (comma)
|
||||||
*mxname = safe_string_alloc(optarg);
|
*(comma++) = 0;
|
||||||
break;
|
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':
|
case 't':
|
||||||
if (!canonicalise(optarg))
|
if (!canonicalise(optarg))
|
||||||
@@ -371,7 +382,9 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
if (!canonicalise(optarg))
|
if (strcmp (optarg, "#") == 0)
|
||||||
|
flags |= OPT_RESOLV_DOMAIN;
|
||||||
|
else if (!canonicalise(optarg))
|
||||||
option = '?';
|
option = '?';
|
||||||
else
|
else
|
||||||
*domain_suffix = safe_string_alloc(optarg);
|
*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
|
/* new->name may be NULL if someone does
|
||||||
"interface=" to disable all interfaces except loop. */
|
"interface=" to disable all interfaces except loop. */
|
||||||
new->name = safe_string_alloc(optarg);
|
new->name = safe_string_alloc(optarg);
|
||||||
|
new->isloop = new->used = 0;
|
||||||
if (strchr(optarg, ':'))
|
if (strchr(optarg, ':'))
|
||||||
flags |= OPT_NOWILD;
|
flags |= OPT_NOWILD;
|
||||||
break;
|
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 */
|
/* # matches everything and becomes a zero length domain string */
|
||||||
if (strcmp(optarg, "#") == 0)
|
if (strcmp(optarg, "#") == 0)
|
||||||
domain = "";
|
domain = "";
|
||||||
else if (!canonicalise(optarg))
|
else if (!canonicalise(optarg) && strlen(optarg) != 0)
|
||||||
option = '?';
|
option = '?';
|
||||||
else
|
else
|
||||||
domain = safe_string_alloc(optarg); /* NULL if strlen is zero */
|
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
|
/* only one of these need be specified: the other defaults to the
|
||||||
host-name */
|
host-name */
|
||||||
if ((flags & OPT_LOCALMX) || *mxname || *mxtarget)
|
if ((flags & OPT_LOCALMX) || *mxnames || *mxtarget)
|
||||||
{
|
{
|
||||||
if (gethostname(buff, MAXDNAME) == -1)
|
if (gethostname(buff, MAXDNAME) == -1)
|
||||||
die("cannot get host-name: %s", NULL);
|
die("cannot get host-name: %s", NULL);
|
||||||
|
|
||||||
if (!*mxname)
|
if (!*mxnames)
|
||||||
*mxname = safe_string_alloc(buff);
|
{
|
||||||
|
*mxnames = safe_malloc(sizeof(struct mx_record));
|
||||||
|
(*mxnames)->next = NULL;
|
||||||
|
(*mxnames)->mxtarget = NULL;
|
||||||
|
(*mxnames)->mxname = safe_string_alloc(buff);
|
||||||
|
}
|
||||||
|
|
||||||
if (!*mxtarget)
|
if (!*mxtarget)
|
||||||
*mxtarget = safe_string_alloc(buff);
|
*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;
|
*resolv_files = 0;
|
||||||
else if (*resolv_files && (*resolv_files)->next && (flags & OPT_NO_POLL))
|
else if (*resolv_files && (*resolv_files)->next && (flags & OPT_NO_POLL))
|
||||||
die("only one resolv.conf file allowed in no-poll mode.", NULL);
|
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;
|
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 */
|
/* 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,
|
char *mxtarget, unsigned int options, time_t now,
|
||||||
unsigned long local_ttl, char *name)
|
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 (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++;
|
anscount++;
|
||||||
ans = 1;
|
ans = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user