Commit 26128d27 authored by Simon Kelley's avatar Simon Kelley

import of dnsmasq-2.17.tar.gz

parent fd9fa481
...@@ -1253,3 +1253,44 @@ version 2.16 ...@@ -1253,3 +1253,44 @@ version 2.16
Added dynamic-dnsmasq from Peter Willis to the contrib Added dynamic-dnsmasq from Peter Willis to the contrib
section. section.
version 2.17
Correctly deduce the size of numeric dhcp-options, rather
than making wild guesses. Also cope with negative values.
Fixed use of C library reserved symbol "index" which broke
under certain combinations of library and compiler.
Make bind-interfaces work for IPv6 interfaces too.
Warn if an interface is given for listening which doesn't
currently exist when not in bind-interfaces mode. (This is
already a fatal error when bind-interfaces is set.)
Allow the --interface and --except-interface options to
take a comma-seperated list of interfaces.
Tweak --dhcp-userclass matching code to work with the
ISC dhclient which violates RFC3004 unless its
configuration is very warped. Thanks to Cedric Duval for
the bug report.
Allow more than one network-id tag in a dhcp-option. All
the tags must match to enable the option.
Added dhcp-ignore option to disable classes of hosts based
on network-id tags. Also allow BOOTP options to be
controlled by network tags.
Fill in sname, file and siaddr fields in replies to
DHCPINFORM messages.
Don't send NAK replies to DHCPREQUEST packets for disabled
clients. Credit to Cedric Duval for spotting this.
Fix rare crash associated with long DNS names and CNAME
records. Thanks to Holger_Hoffstatte and especially Steve
Grecni for help chasing that one down.
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
############################################################################### ###############################################################################
Name: dnsmasq Name: dnsmasq
Version: 2.16 Version: 2.17
Release: 1 Release: 1
Copyright: GPL Copyright: GPL
Group: System Environment/Daemons Group: System Environment/Daemons
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
############################################################################### ###############################################################################
Name: dnsmasq Name: dnsmasq
Version: 2.16 Version: 2.17
Release: 1 Release: 1
Copyright: GPL Copyright: GPL
Group: Productivity/Networking/DNS/Servers Group: Productivity/Networking/DNS/Servers
......
...@@ -366,7 +366,7 @@ have exactly the same effect as ...@@ -366,7 +366,7 @@ have exactly the same effect as
.B --dhcp-host .B --dhcp-host
options containing the same information. options containing the same information.
.TP .TP
.B \-O, --dhcp-option=[network-id,]<opt>,[<value>[,<value>]] .B \-O, --dhcp-option=[<network-id>,[<network-id>,]]<opt>,[<value>[,<value>]]
Specfify different or extra options to DHCP clients. By default, Specfify different or extra options to DHCP clients. By default,
dnsmasq sends some standard options to DHCP clients, the netmask and dnsmasq sends some standard options to DHCP clients, the netmask and
broadcast address are set to the same as the host running dnsmasq, and broadcast address are set to the same as the host running dnsmasq, and
...@@ -382,12 +382,10 @@ and to set the time-server address to 192.168.0.4, do ...@@ -382,12 +382,10 @@ and to set the time-server address to 192.168.0.4, do
The special address 0.0.0.0 is taken to mean "the address of the The special address 0.0.0.0 is taken to mean "the address of the
machine running dnsmasq". Data types allowed are comma seperated machine running dnsmasq". Data types allowed are comma seperated
dotted-quad IP addresses, a decimal number, colon-seperated hex digits dotted-quad IP addresses, a decimal number, colon-seperated hex digits
and a text string. If the optional network-id is given then and a text string. If the optional network-ids are given then
this option is only sent to machines on the network whose dhcp-range this option is only sent when all the network-ids are matched.
contains a matching network-id.
Be careful: no checking is done that the correct type of data for the Be careful: no checking is done that the correct type of data for the
option number is sent, and there are option numbers for which it is not option number is sent, it is quite possible to
possible to generate the correct data type; it is quite possible to
persuade dnsmasq to generate illegal DHCP packets with injudicious use persuade dnsmasq to generate illegal DHCP packets with injudicious use
of this flag. of this flag.
.TP .TP
...@@ -412,10 +410,17 @@ to different classes of hosts. It is possible, for instance to use ...@@ -412,10 +410,17 @@ to different classes of hosts. It is possible, for instance to use
this to set a different printer server for hosts in the class this to set a different printer server for hosts in the class
"accounts" than for hosts in the class "engineering". "accounts" than for hosts in the class "engineering".
.TP .TP
.B \-M, --dhcp-boot=<filename>,[<servername>[,<server address>]] .B \ -J, --dhcp-ignore=<network-id>[,<network-id>]
When all the given network-ids match the set of network-ids derived
from the net, host, vendor and user classes, ignore the host and do
not allocate it a DHCP lease.
.TP
.B \-M, --dhcp-boot=[net:<network-id>,]<filename>,[<servername>[,<server address>]]
Set BOOTP options to be returned by the DHCP server. These are needed Set BOOTP options to be returned by the DHCP server. These are needed
for machines which network boot, and tell the machine where to collect for machines which network boot, and tell the machine where to collect
its initial configuration. its initial configuration. If the optional network-id(s) are given,
they must match for this configuration to be sent. Note that
network-ids are prefixed by "net:" to distinguish them.
.TP .TP
.B \-X, --dhcp-lease-max=<number> .B \-X, --dhcp-lease-max=<number>
Limits dnsmasq to the specified maximum number of DHCP leases. The Limits dnsmasq to the specified maximum number of DHCP leases. The
...@@ -540,6 +545,21 @@ and run dnsmasq with the ...@@ -540,6 +545,21 @@ and run dnsmasq with the
option. This second technique allows for dynamic update of the server option. This second technique allows for dynamic update of the server
addresses by PPP or DHCP. addresses by PPP or DHCP.
.PP .PP
The network-id system works as follows: For each DHCP request, dnsmasq
collects a set of valid network-id tags, one from the
.B dhcp-range
used to allocate the address, one from any matching
.B dhcp-host
and possibly many from matching vendor classes and user
classes sent by the DHCP client. Any
.B dhcp-option
which has network-id tags will be used in preference to an untagged
.B dhcp-option,
provided that _all_ the tags match somewhere in the
set collected as described above. The prefix '#' on a tag means 'not'
so --dhcp=option=#purple,3,1.2.3.4 sends the option when the
network-id tag purple is not in the set of valid tags.
.PP
The DHCP server in dnsmasq will function as a BOOTP server also, The DHCP server in dnsmasq will function as a BOOTP server also,
provided that the MAC address and IP address for clients are given, provided that the MAC address and IP address for clients are given,
either using either using
......
...@@ -23,7 +23,8 @@ Mac OS X. ...@@ -23,7 +23,8 @@ Mac OS X.
Dnsmasq is included in at least the following Linux distributions: Dnsmasq is included in at least the following Linux distributions:
Gentoo, Debian, Slackware, Suse, Gentoo, Debian, Slackware, Suse,
Smoothwall, IP-Cop, floppyfw, Firebox, LEAF, Freesco, CoyoteLinux and Smoothwall, IP-Cop, floppyfw, Firebox, LEAF, 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 and the m0n0wall project.
<P> <P>
Dnsmasq provides the following features: Dnsmasq provides the following features:
<DIR> <DIR>
...@@ -41,22 +42,18 @@ machine: If the names of local machines are there, then they can all ...@@ -41,22 +42,18 @@ machine: If the names of local machines are there, then they can all
be addressed without having to maintain /etc/hosts on each machine. be addressed without having to maintain /etc/hosts on each machine.
</LI> </LI>
<LI> <LI>
Dnsmasq will serve names from the DHCP leases file on the firewall machine: The integrated DHCP server supports static and dynamic DHCP leases and
If machines specify a hostname when they take out a DHCP lease, then they are multiple networks and IP ranges. It works across BOOTP relays and
addressable in the local DNS. <B>UPDATE</B> Dnsmasq version 2 now offers an integrated DHCP server supports DHCP options including RFC3397 DNS search lists.
instead of the lease file reader. This gives better control of the Machines which are configured by DHCP have their names automatically
interaction with new functions (for example fixed IP leasess and included in the DNS and the names can specified by each machine or
attaching names to ethernet addresses centrally) it's also much centrally by associating a name with a MAC address in the dnsmasq
smaller than dnsmasq and ISC dhcpd which is important for router distros. config file.
</LI> </LI>
<LI> <LI>
Dnsmasq caches internet addresses (A records and AAAA records) and address-to-name Dnsmasq caches internet addresses (A records and AAAA records) and address-to-name
mappings (PTR records), reducing the load on upstream servers and mappings (PTR records), reducing the load on upstream servers and
improving performance (especially on modem connections). From version improving performance (especially on modem connections).
0.95 the cache honours time-to-live information and removes old
records as they expire. From version 0.996 dnsmasq does negative
caching. From version 1.2 dnsmasq supports IPv6 addresses, both
in its cache and in /etc/hosts.
</LI> </LI>
<LI> <LI>
Dnsmasq can be configured to automatically pick up the addresses of Dnsmasq can be configured to automatically pick up the addresses of
...@@ -76,14 +73,8 @@ upstream servers handling only those domains. This makes integration ...@@ -76,14 +73,8 @@ upstream servers handling only those domains. This makes integration
with private DNS systems easy. with private DNS systems easy.
</LI> </LI>
<LI> <LI>
Dnsmasq can be configured to return an MX record Dnsmasq supports MX records and can be configured to return MX records
for the firewall host. This makes it easy to configure the mailer on the local for any or all local machines.
machines to forward all mail to the central mailer on the firewall host. Never
lose root messages from your machines again!
</LI>
<LI>
For version 1.15 dnsmasq has a facility to work around Verisign's infamous wildcard A record
in the .com and .net TLDs
</LI> </LI>
</DIR> </DIR>
...@@ -115,12 +106,19 @@ bzip2 dnsmasq-zzz.tar ...@@ -115,12 +106,19 @@ bzip2 dnsmasq-zzz.tar
Ulrich Ivens has a nice HOWTO in German on installing dnsmasq at <A Ulrich Ivens has a nice HOWTO in German on installing dnsmasq at <A
HREF="http://howto.linux-hardware-shop.de/dnsmasq.html">http://howto.linux-hardware-shop.de/dnsmasq.html</A> HREF="http://howto.linux-hardware-shop.de/dnsmasq.html">http://howto.linux-hardware-shop.de/dnsmasq.html</A>
and Damien Raude-Morvan has one in French at <A HREF="http://www.drazzib.com/docs-dnsmasq.html">http://www.drazzib.com/docs-dnsmasq.html</A> and Damien Raude-Morvan has one in French at <A HREF="http://www.drazzib.com/docs-dnsmasq.html">http://www.drazzib.com/docs-dnsmasq.html</A>
There is a good article about dnsmasq at <A
HREF="http://www.enterprisenetworkingplanet.com/netos/article.php/3377351">http://www.enterprisenetworkingplanet.com/netos/article.php/3377351</A>
<H2>License.</H2> <H2>License.</H2>
Dnsmasq is distributed under the GPL. See the file COPYING in the distribution Dnsmasq is distributed under the GPL. See the file COPYING in the distribution
for details. for details.
<H2>Contact.</H2> <H2>Contact.</H2>
Dnsmasq was written by Simon Kelley. You can contact me at <A HREF="mailto:simon@thekelleys.org.uk">simon@thekelleys.org.uk</A>. Bugreports, patches, and suggestions for improvements gratefully accepted. There is a dnsmasq mailing list at <A
HREF="http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss">
http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss</A> which should be the
first location for queries, bugreports, suggestions etc.
Dnsmasq was written by Simon Kelley. You can contact me at <A
HREF="mailto:simon@thekelleys.org.uk">simon@thekelleys.org.uk</A>.
</BODY> </BODY>
...@@ -17,7 +17,7 @@ static struct crec *dhcp_inuse, *dhcp_spare, *new_chain; ...@@ -17,7 +17,7 @@ static struct crec *dhcp_inuse, *dhcp_spare, *new_chain;
static int cache_inserted, cache_live_freed, insert_error; static int cache_inserted, cache_live_freed, insert_error;
static union bigname *big_free; static union bigname *big_free;
static int bignames_left, log_queries, cache_size, hash_size; static int bignames_left, log_queries, cache_size, hash_size;
static int index; static int uid;
static void cache_free(struct crec *crecp); static void cache_free(struct crec *crecp);
static void cache_unlink(struct crec *crecp); static void cache_unlink(struct crec *crecp);
...@@ -36,7 +36,7 @@ void cache_init(int size, int logq) ...@@ -36,7 +36,7 @@ void cache_init(int size, int logq)
cache_size = size; cache_size = size;
big_free = NULL; big_free = NULL;
bignames_left = size/10; bignames_left = size/10;
index = 0; uid = 0;
cache_inserted = cache_live_freed = 0; cache_inserted = cache_live_freed = 0;
...@@ -48,7 +48,7 @@ void cache_init(int size, int logq) ...@@ -48,7 +48,7 @@ void cache_init(int size, int logq)
{ {
cache_link(crecp); cache_link(crecp);
crecp->flags = 0; crecp->flags = 0;
crecp->uid = index++; crecp->uid = uid++;
} }
} }
...@@ -85,7 +85,7 @@ static void cache_free(struct crec *crecp) ...@@ -85,7 +85,7 @@ static void cache_free(struct crec *crecp)
{ {
crecp->flags &= ~F_FORWARD; crecp->flags &= ~F_FORWARD;
crecp->flags &= ~F_REVERSE; crecp->flags &= ~F_REVERSE;
crecp->uid = index++; /* invalidate CNAMES pointing to this. */ crecp->uid = uid++; /* invalidate CNAMES pointing to this. */
if (cache_tail) if (cache_tail)
cache_tail->next = crecp; cache_tail->next = crecp;
...@@ -673,7 +673,7 @@ void cache_add_dhcp_entry(struct daemon *daemon, char *host_name, ...@@ -673,7 +673,7 @@ void cache_add_dhcp_entry(struct daemon *daemon, char *host_name,
if (!host_name) if (!host_name)
return; return;
if ((crec = cache_find_by_name(NULL, host_name, 0, F_IPV4))) if ((crec = cache_find_by_name(NULL, host_name, 0, F_IPV4 | F_CNAME)))
{ {
if (crec->flags & F_HOSTS) if (crec->flags & F_HOSTS)
{ {
...@@ -681,7 +681,7 @@ void cache_add_dhcp_entry(struct daemon *daemon, char *host_name, ...@@ -681,7 +681,7 @@ void cache_add_dhcp_entry(struct daemon *daemon, char *host_name,
{ {
strcpy(daemon->namebuff, inet_ntoa(crec->addr.addr.addr.addr4)); strcpy(daemon->namebuff, inet_ntoa(crec->addr.addr.addr.addr4));
syslog(LOG_WARNING, syslog(LOG_WARNING,
"not giving name %s to the DHCP lease of %s because" "not giving name %s to the DHCP lease of %s because "
"the name exists in %s with address %s", "the name exists in %s with address %s",
host_name, inet_ntoa(*host_address), host_name, inet_ntoa(*host_address),
record_source(daemon->addn_hosts, crec->uid), daemon->namebuff); record_source(daemon->addn_hosts, crec->uid), daemon->namebuff);
...@@ -689,7 +689,7 @@ void cache_add_dhcp_entry(struct daemon *daemon, char *host_name, ...@@ -689,7 +689,7 @@ void cache_add_dhcp_entry(struct daemon *daemon, char *host_name,
return; return;
} }
else if (!(crec->flags & F_DHCP)) else if (!(crec->flags & F_DHCP))
cache_scan_free(host_name, NULL, 0, F_IPV4 | F_FORWARD); cache_scan_free(host_name, NULL, 0, crec->flags & (F_IPV4 | F_CNAME | F_FORWARD));
} }
if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, F_IPV4))) if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, F_IPV4)))
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
/* Author's email: simon@thekelleys.org.uk */ /* Author's email: simon@thekelleys.org.uk */
#define VERSION "2.16" #define VERSION "2.17"
#define FTABSIZ 150 /* max number of outstanding requests */ #define FTABSIZ 150 /* max number of outstanding requests */
#define MAX_PROCS 20 /* max no children for TCP requests */ #define MAX_PROCS 20 /* max no children for TCP requests */
......
...@@ -47,6 +47,8 @@ void dhcp_init(struct daemon *daemon) ...@@ -47,6 +47,8 @@ void dhcp_init(struct daemon *daemon)
daemon->dhcpfd = fd; daemon->dhcpfd = fd;
if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1 || if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1 ||
(flags = fcntl(fd, F_GETFL, 0)) == -1 ||
fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1 ||
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) || setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) ||
setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1) setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
die("cannot create ICMP raw socket: %s.", NULL); die("cannot create ICMP raw socket: %s.", NULL);
...@@ -73,8 +75,6 @@ void dhcp_init(struct daemon *daemon) ...@@ -73,8 +75,6 @@ void dhcp_init(struct daemon *daemon)
socket receive buffer size to one to avoid that. (zero is socket receive buffer size to one to avoid that. (zero is
rejected as non-sensical by some BSD kernels) */ rejected as non-sensical by some BSD kernels) */
if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETHERTYPE_IP))) == -1 || if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETHERTYPE_IP))) == -1 ||
(flags = fcntl(fd, F_GETFL, 0)) == -1 ||
fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1 ||
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) == -1) setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) == -1)
die("cannot create DHCP packet socket: %s. " die("cannot create DHCP packet socket: %s. "
"Is CONFIG_PACKET enabled in your kernel?", NULL); "Is CONFIG_PACKET enabled in your kernel?", NULL);
...@@ -358,8 +358,7 @@ void dhcp_packet(struct daemon *daemon, time_t now) ...@@ -358,8 +358,7 @@ void dhcp_packet(struct daemon *daemon, time_t now)
iov[0].iov_len = sizeof(struct ether_header); iov[0].iov_len = sizeof(struct ether_header);
iov[1].iov_base = (char *)rawpacket; iov[1].iov_base = (char *)rawpacket;
iov[1].iov_len = ntohs(rawpacket->ip.ip_len); iov[1].iov_len = ntohs(rawpacket->ip.ip_len);
while (writev(daemon->dhcp_raw_fd, iov, 2) == -1 && while (writev(daemon->dhcp_raw_fd, iov, 2) == -1 && retry_send());
errno == EINTR);
#else #else
struct sockaddr_ll dest; struct sockaddr_ll dest;
...@@ -370,7 +369,7 @@ void dhcp_packet(struct daemon *daemon, time_t now) ...@@ -370,7 +369,7 @@ void dhcp_packet(struct daemon *daemon, time_t now)
memcpy(dest.sll_addr, hwdest, ETHER_ADDR_LEN); memcpy(dest.sll_addr, hwdest, ETHER_ADDR_LEN);
while (sendto(daemon->dhcp_raw_fd, rawpacket, ntohs(rawpacket->ip.ip_len), while (sendto(daemon->dhcp_raw_fd, rawpacket, ntohs(rawpacket->ip.ip_len),
0, (struct sockaddr *)&dest, sizeof(dest)) == -1 && 0, (struct sockaddr *)&dest, sizeof(dest)) == -1 &&
errno == EINTR); retry_send());
#endif #endif
} }
} }
......
...@@ -30,6 +30,7 @@ int main (int argc, char **argv) ...@@ -30,6 +30,7 @@ int main (int argc, char **argv)
struct irec *interfaces; struct irec *interfaces;
struct sigaction sigact; struct sigaction sigact;
sigset_t sigmask; sigset_t sigmask;
struct iname *if_tmp;
sighup = 1; /* init cache the first time through */ sighup = 1; /* init cache the first time through */
sigusr1 = 0; /* but don't dump */ sigusr1 = 0; /* but don't dump */
...@@ -92,7 +93,6 @@ int main (int argc, char **argv) ...@@ -92,7 +93,6 @@ int main (int argc, char **argv)
if (daemon->options & OPT_NOWILD) if (daemon->options & OPT_NOWILD)
{ {
struct iname *if_tmp;
daemon->listeners = create_bound_listeners(interfaces, daemon->port); daemon->listeners = create_bound_listeners(interfaces, daemon->port);
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next) for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
...@@ -263,6 +263,11 @@ int main (int argc, char **argv) ...@@ -263,6 +263,11 @@ int main (int argc, char **argv)
if (bind_fallback) if (bind_fallback)
syslog(LOG_WARNING, "setting --bind-interfaces option because of OS limitations"); syslog(LOG_WARNING, "setting --bind-interfaces option because of OS limitations");
if (!(daemon->options & OPT_NOWILD))
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
if (if_tmp->name && !if_tmp->used)
syslog(LOG_WARNING, "warning: interface %s does not currently exist", if_tmp->name);
if (daemon->dhcp) if (daemon->dhcp)
{ {
struct dhcp_context *dhcp_tmp; struct dhcp_context *dhcp_tmp;
...@@ -288,13 +293,12 @@ int main (int argc, char **argv) ...@@ -288,13 +293,12 @@ int main (int argc, char **argv)
"DHCP, IP range %s -- %s, lease time %s", "DHCP, IP range %s -- %s, lease time %s",
daemon->dhcp_buff, inet_ntoa(dhcp_tmp->end), time); daemon->dhcp_buff, inet_ntoa(dhcp_tmp->end), time);
} }
}
#ifdef HAVE_BROKEN_RTC #ifdef HAVE_BROKEN_RTC
if (daemon->dhcp) syslog(LOG_INFO, "DHCP, %s will be written every %ds", daemon->lease_file, daemon->min_leasetime/3);
syslog(LOG_INFO, "DHCP, %s will be written every %ds", daemon->lease_file, daemon->min_leasetime/3);
#endif #endif
}
if (!(daemon->options & OPT_DEBUG) && (getuid() == 0 || geteuid() == 0)) if (!(daemon->options & OPT_DEBUG) && (getuid() == 0 || geteuid() == 0))
syslog(LOG_WARNING, "running as root"); syslog(LOG_WARNING, "running as root");
......
...@@ -269,6 +269,10 @@ struct dhcp_netid { ...@@ -269,6 +269,10 @@ struct dhcp_netid {
struct dhcp_netid *next; struct dhcp_netid *next;
}; };
struct dhcp_netid_list {
struct dhcp_netid *list;
struct dhcp_netid_list *next;
};
struct dhcp_config { struct dhcp_config {
unsigned int flags; unsigned int flags;
int clid_len; /* length of client identifier */ int clid_len; /* length of client identifier */
...@@ -293,12 +297,19 @@ struct dhcp_config { ...@@ -293,12 +297,19 @@ struct dhcp_config {
struct dhcp_opt { struct dhcp_opt {
int opt, len, is_addr; int opt, len, is_addr;
unsigned char *val; unsigned char *val;
char *netid; struct dhcp_netid *netid;
struct dhcp_opt *next; struct dhcp_opt *next;
}; };
struct dhcp_boot {
char *file, *sname;
struct in_addr next_server;
struct dhcp_netid *netid;
struct dhcp_boot *next;
};
struct dhcp_vendor { struct dhcp_vendor {
int len, is_vendor, used; int len, is_vendor;
char *data; char *data;
struct dhcp_netid netid; struct dhcp_netid netid;
struct dhcp_vendor *next; struct dhcp_vendor *next;
...@@ -361,9 +372,8 @@ struct daemon { ...@@ -361,9 +372,8 @@ struct daemon {
struct dhcp_config *dhcp_conf; struct dhcp_config *dhcp_conf;
struct dhcp_opt *dhcp_opts; struct dhcp_opt *dhcp_opts;
struct dhcp_vendor *dhcp_vendors; struct dhcp_vendor *dhcp_vendors;
char *dhcp_file; struct dhcp_boot *boot_config;
char *dhcp_sname; struct dhcp_netid_list *dhcp_ignore;
struct in_addr dhcp_next_server;
int dhcp_max; int dhcp_max;
unsigned int min_leasetime; unsigned int min_leasetime;
struct doctor *doctors; struct doctor *doctors;
......
...@@ -65,45 +65,43 @@ static void send_from(int fd, int nowild, char *packet, int len, ...@@ -65,45 +65,43 @@ static void send_from(int fd, int nowild, char *packet, int len,
msg.msg_iov = iov; msg.msg_iov = iov;
msg.msg_iovlen = 1; msg.msg_iovlen = 1;
if (!nowild && to->sa.sa_family == AF_INET) if (!nowild)
{ {
struct cmsghdr *cmptr;
msg.msg_control = &control_u; msg.msg_control = &control_u;
msg.msg_controllen = sizeof(control_u); msg.msg_controllen = sizeof(control_u);
{ cmptr = CMSG_FIRSTHDR(&msg);
struct cmsghdr *cmptr = CMSG_FIRSTHDR(&msg);
if (to->sa.sa_family == AF_INET)
{
#if defined(IP_PKTINFO) #if defined(IP_PKTINFO)
struct in_pktinfo *pkt = (struct in_pktinfo *)CMSG_DATA(cmptr); struct in_pktinfo *pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
pkt->ipi_ifindex = 0; pkt->ipi_ifindex = 0;
pkt->ipi_spec_dst = source->addr.addr4; pkt->ipi_spec_dst = source->addr.addr4;
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
cmptr->cmsg_level = SOL_IP; cmptr->cmsg_level = SOL_IP;
cmptr->cmsg_type = IP_PKTINFO; cmptr->cmsg_type = IP_PKTINFO;
#elif defined(IP_SENDSRCADDR) #elif defined(IP_SENDSRCADDR)
struct in_addr *a = (struct in_addr *)CMSG_DATA(cmptr); struct in_addr *a = (struct in_addr *)CMSG_DATA(cmptr);
*a = source->addr.addr4; *a = source->addr.addr4;
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
cmptr->cmsg_level = IPPROTO_IP; cmptr->cmsg_level = IPPROTO_IP;
cmptr->cmsg_type = IP_SENDSRCADDR; cmptr->cmsg_type = IP_SENDSRCADDR;
#endif #endif
} }
}
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if (to->sa.sa_family == AF_INET6) else
{ {
msg.msg_control = &control_u; struct in6_pktinfo *pkt = (struct in6_pktinfo *)CMSG_DATA(cmptr);
msg.msg_controllen = sizeof(control_u); pkt->ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */
{ pkt->ipi6_addr = source->addr.addr6;
struct cmsghdr *cmptr = CMSG_FIRSTHDR(&msg); msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
struct in6_pktinfo *pkt = (struct in6_pktinfo *)CMSG_DATA(cmptr); cmptr->cmsg_type = IPV6_PKTINFO;
pkt->ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */ cmptr->cmsg_level = IPV6_LEVEL;
pkt->ipi6_addr = source->addr.addr6; }
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
cmptr->cmsg_type = IPV6_PKTINFO;
cmptr->cmsg_level = IPV6_LEVEL;
}
}
#endif #endif
}
retry: retry:
if (sendmsg(fd, &msg, 0) == -1) if (sendmsg(fd, &msg, 0) == -1)
...@@ -462,7 +460,7 @@ void reply_query(struct serverfd *sfd, struct daemon *daemon, time_t now) ...@@ -462,7 +460,7 @@ void reply_query(struct serverfd *sfd, struct daemon *daemon, time_t now)
{ {
header->id = htons(forward->orig_id); header->id = htons(forward->orig_id);
header->ra = 1; /* recursion if available */ header->ra = 1; /* recursion if available */
send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, n, send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, n,
&forward->source, &forward->dest, forward->iface); &forward->source, &forward->dest, forward->iface);
forward->new_id = 0; /* cancel */ forward->new_id = 0; /* cancel */
} }
...@@ -476,7 +474,6 @@ void receive_query(struct listener *listen, struct daemon *daemon, time_t now) ...@@ -476,7 +474,6 @@ void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
unsigned short type; unsigned short type;
struct iname *tmp; struct iname *tmp;
struct all_addr dst_addr; struct all_addr dst_addr;
int check_dst = !(daemon->options & OPT_NOWILD);
int m, n, if_index = 0; int m, n, if_index = 0;
struct iovec iov[1]; struct iovec iov[1];
struct msghdr msg; struct msghdr msg;
...@@ -508,57 +505,55 @@ void receive_query(struct listener *listen, struct daemon *daemon, time_t now) ...@@ -508,57 +505,55 @@ void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
if ((n = recvmsg(listen->fd, &msg, 0)) == -1) if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
return; return;
if (n < (int)sizeof(HEADER) || header->qr)
return;
source_addr.sa.sa_family = listen->family; source_addr.sa.sa_family = listen->family;
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if (listen->family == AF_INET6) if (listen->family == AF_INET6)
{ source_addr.in6.sin6_flowinfo = htonl(0);
check_dst = 1;
source_addr.in6.sin6_flowinfo = htonl(0);
}
#endif #endif
if (check_dst && msg.msg_controllen < sizeof(struct cmsghdr)) if (!(daemon->options & OPT_NOWILD))
return; {
struct ifreq ifr;
if (msg.msg_controllen < sizeof(struct cmsghdr))
return;
#if defined(IP_PKTINFO) #if defined(IP_PKTINFO)
if (check_dst && listen->family == AF_INET) if (listen->family == AF_INET)
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO) if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
{
dst_addr.addr.addr4 = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst;
if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
}
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
if (listen->family == AF_INET)
{ {
dst_addr.addr.addr4 = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst; for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex; if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
dst_addr.addr.addr4 = *((struct in_addr *)CMSG_DATA(cmptr));
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
} }
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
if (check_dst && listen->family == AF_INET)
{
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
dst_addr.addr.addr4 = *((struct in_addr *)CMSG_DATA(cmptr));
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
}
#endif #endif
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if (listen->family == AF_INET6) if (listen->family == AF_INET6)
{ {
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == IPV6_PKTINFO) if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == IPV6_PKTINFO)
{ {
dst_addr.addr.addr6 = ((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_addr; dst_addr.addr.addr6 = ((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_addr;
if_index =((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_ifindex; if_index =((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_ifindex;
} }
} }
#endif #endif
if (n < (int)sizeof(HEADER) || header->qr) /* enforce available interface configuration */
return;
/* enforce available interface configuration */
if (check_dst)
{
struct ifreq ifr;
if (if_index == 0) if (if_index == 0)
return; return;
......
...@@ -356,34 +356,37 @@ struct listener *create_bound_listeners(struct irec *interfaces, int port) ...@@ -356,34 +356,37 @@ struct listener *create_bound_listeners(struct irec *interfaces, int port)
struct irec *iface; struct irec *iface;
int flags = port, opt = 1; int flags = port, opt = 1;
/* Create bound listeners only for IPv4, IPv6 always binds the wildcard */ for (iface = interfaces ;iface; iface = iface->next)
{
struct listener *new = safe_malloc(sizeof(struct listener));
new->family = iface->addr.sa.sa_family;
new->next = listeners;
listeners = new;
if ((new->tcpfd = socket(iface->addr.sa.sa_family, SOCK_STREAM, 0)) == -1 ||
(new->fd = socket(iface->addr.sa.sa_family, SOCK_DGRAM, 0)) == -1 ||
setsockopt(new->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
setsockopt(new->tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
/* See Stevens 16.6 */
(flags = fcntl(new->tcpfd, F_GETFL, 0)) == -1 ||
fcntl(new->tcpfd, F_SETFL, flags | O_NONBLOCK) == -1 ||
(flags = fcntl(new->fd, F_GETFL, 0)) == -1 ||
fcntl(new->fd, F_SETFL, flags | O_NONBLOCK) == -1)
die("failed to create listening socket: %s", NULL);
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if (!create_ipv6_listener(&listeners, port)) if (iface->addr.sa.sa_family == AF_INET6)
die("failed to to create listening socket: %s", NULL); {
if (setsockopt(new->fd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
setsockopt(new->tcpfd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
die("failed to set IPV6 options on listening socket: %s", NULL);
}
#endif #endif
for (iface = interfaces ;iface; iface = iface->next) if (bind(new->tcpfd, &iface->addr.sa, sa_len(&iface->addr)) == -1 ||
if (iface->addr.sa.sa_family == AF_INET) bind(new->fd, &iface->addr.sa, sa_len(&iface->addr)) == -1 ||
{ listen(new->tcpfd, 5) == -1)
struct listener *new = safe_malloc(sizeof(struct listener)); die("failed to bind listening socket: %s", NULL);
new->family = iface->addr.sa.sa_family; }
new->next = listeners;
listeners = new;
if ((new->tcpfd = socket(iface->addr.sa.sa_family, SOCK_STREAM, 0)) == -1 ||
(new->fd = socket(iface->addr.sa.sa_family, SOCK_DGRAM, 0)) == -1 ||
setsockopt(new->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
setsockopt(new->tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
/* See Stevens 16.6 */
(flags = fcntl(new->tcpfd, F_GETFL, 0)) == -1 ||
fcntl(new->tcpfd, F_SETFL, flags | O_NONBLOCK) == -1 ||
(flags = fcntl(new->fd, F_GETFL, 0)) == -1 ||
fcntl(new->fd, F_SETFL, flags | O_NONBLOCK) == -1 ||
bind(new->tcpfd, &iface->addr.sa, sa_len(&iface->addr)) == -1 ||
bind(new->fd, &iface->addr.sa, sa_len(&iface->addr)) == -1 ||
listen(new->tcpfd, 5) == -1)
die("failed to to create listening socket: %s", NULL);
}
return listeners; return listeners;
} }
......
This diff is collapsed.
...@@ -653,7 +653,7 @@ void extract_addresses(HEADER *header, unsigned int qlen, char *name, time_t now ...@@ -653,7 +653,7 @@ void extract_addresses(HEADER *header, unsigned int qlen, char *name, time_t now
if (!cname_count--) if (!cname_count--)
return; /* looped CNAMES */ return; /* looped CNAMES */
newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD); newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD);
if (cpp) if (newc && cpp)
{ {
cpp->addr.cname.cache = newc; cpp->addr.cname.cache = newc;
cpp->addr.cname.uid = newc->uid; cpp->addr.cname.uid = newc->uid;
...@@ -673,7 +673,7 @@ void extract_addresses(HEADER *header, unsigned int qlen, char *name, time_t now ...@@ -673,7 +673,7 @@ void extract_addresses(HEADER *header, unsigned int qlen, char *name, time_t now
if (aqtype == T_A) if (aqtype == T_A)
dns_doctor(header, daemon->doctors, (struct in_addr *)p1); dns_doctor(header, daemon->doctors, (struct in_addr *)p1);
newc = cache_insert(name, (struct all_addr *)p1, now, attl, flags | F_FORWARD); newc = cache_insert(name, (struct all_addr *)p1, now, attl, flags | F_FORWARD);
if (cpp) if (newc && cpp)
{ {
cpp->addr.cname.cache = newc; cpp->addr.cname.cache = newc;
cpp->addr.cname.uid = newc->uid; cpp->addr.cname.uid = newc->uid;
...@@ -700,7 +700,7 @@ void extract_addresses(HEADER *header, unsigned int qlen, char *name, time_t now ...@@ -700,7 +700,7 @@ void extract_addresses(HEADER *header, unsigned int qlen, char *name, time_t now
if (ttl || cpp) if (ttl || cpp)
{ {
newc = cache_insert(name, (struct all_addr *)p, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags); newc = cache_insert(name, (struct all_addr *)p, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags);
if (cpp) if (newc && cpp)
{ {
cpp->addr.cname.cache = newc; cpp->addr.cname.cache = newc;
cpp->addr.cname.uid = newc->uid; cpp->addr.cname.uid = newc->uid;
...@@ -807,7 +807,7 @@ int check_for_local_domain(char *name, time_t now, struct mx_record *mx) ...@@ -807,7 +807,7 @@ int check_for_local_domain(char *name, time_t now, struct mx_record *mx)
{ {
struct crec *crecp; struct crec *crecp;
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4|F_IPV6)) && if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)) &&
(crecp->flags & (F_HOSTS | F_DHCP))) (crecp->flags & (F_HOSTS | F_DHCP)))
return 1; return 1;
...@@ -1038,7 +1038,7 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon ...@@ -1038,7 +1038,7 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
{ {
unsigned short type = T_A; unsigned short type = T_A;
int addrsz = INADDRSZ; int addrsz = INADDRSZ;
if (flag == F_IPV6) if (flag == F_IPV6)
{ {
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
...@@ -1049,18 +1049,20 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon ...@@ -1049,18 +1049,20 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
#endif #endif
} }
if (qtype != type && qtype != T_ANY && qtype != T_CNAME) if (qtype != type && qtype != T_ANY)
continue; continue;
cname_restart: cname_restart:
crecp = NULL; crecp = NULL;
while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME))) while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)))
{ {
/* don't answer wildcard queries with data not from /etc/hosts
or DHCP leases */
if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
break;
if (crecp->flags & F_CNAME) if (crecp->flags & F_CNAME)
{ {
if (qtype == T_CNAME)
ans = 1;
if (!dryrun) if (!dryrun)
{ {
ansp = add_text_record(header, nameoffset, ansp, crecp->ttd - now, 0, T_CNAME, ansp = add_text_record(header, nameoffset, ansp, crecp->ttd - now, 0, T_CNAME,
...@@ -1068,17 +1070,10 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon ...@@ -1068,17 +1070,10 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
anscount++; anscount++;
log_query(crecp->flags, name, NULL, 0, daemon->addn_hosts, crecp->uid); log_query(crecp->flags, name, NULL, 0, daemon->addn_hosts, crecp->uid);
} }
strcpy(name, cache_get_name(crecp->addr.cname.cache)); strcpy(name, cache_get_name(crecp->addr.cname.cache));
goto cname_restart; goto cname_restart;
} }
if (qtype == T_CNAME)
break;
/* don't answer wildcard queries with data not from /etc/hosts
or DHCP leases */
if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
continue;
if (crecp->flags & F_NEG) if (crecp->flags & F_NEG)
{ {
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment