Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a6bca81f6 | ||
|
|
9e038946a1 | ||
|
|
824af85bdf |
241
CHANGELOG
241
CHANGELOG
@@ -45,7 +45,7 @@ release 0.95 Major rewrite: remove calls to gethostbyname() and talk
|
||||
dnsmasq to serve names to the machine it is running
|
||||
on (put nameserver 127.0.0.1 in /etc/resolv.conf and
|
||||
give dnsmasq the option -r /etc/resolv.dnsmasq)
|
||||
(6) Dnsmasq will re-read it's servers if the
|
||||
(6) Dnsmasq will re-read its servers if the
|
||||
modification time of resolv.conf changes. Along with
|
||||
4 above this allows nameservers to be set
|
||||
automatically by ppp or dhcp.
|
||||
@@ -1076,7 +1076,7 @@ release 2.10
|
||||
|
||||
NAK attempts to renew a pool DHCP lease when a statically
|
||||
allocated address has become available, forcing a host to
|
||||
move to it's allocated address. Lots of people have
|
||||
move to its allocated address. Lots of people have
|
||||
suggested this change and been rebuffed (they know who
|
||||
they are) the straws that broke the camel's back were Tim
|
||||
Cutts and Jamie Lokier.
|
||||
@@ -2343,5 +2343,242 @@ version 2.40
|
||||
inetd is also listening on the same port. Thanks to Erik
|
||||
Brown for spotting the problem.
|
||||
|
||||
version 2.41
|
||||
Remove deprecated calls when compiled against libdbus 1.1.
|
||||
|
||||
Fix "strict-alias" warning in bpf.c
|
||||
|
||||
Reduce dependency on Gnu-make in build system: dnsmasq now
|
||||
builds with system make under OpenBSD.
|
||||
|
||||
Port to Solaris. Dnsmasq 1.x used to run under Solaris,
|
||||
and this release does so again, for Solaris 9 or better.
|
||||
|
||||
Allow the DNS function to be completely disabled, by
|
||||
setting the port to zero "--port=0". The allows dnsmasq to
|
||||
be used as a simple DHCP server, simple TFTP server, or
|
||||
both, but without the DNS server getting in the way.
|
||||
|
||||
Fix a bug where NXDOMAIN could be returned for a query
|
||||
even if the name's value was known for a different query
|
||||
type. This bug could be prodded with
|
||||
--local=/domain/ --address=/name.domain/1.2.3.4
|
||||
An IPv6 query for name.domain would return NXDOMAIN, and
|
||||
not the correct NOERROR. Thanks to Lars Nooden for
|
||||
spotting the bug and Jima for diagnosis of the problem.
|
||||
|
||||
Added per-server stats to the information logged when
|
||||
dnsmasq gets SIGUSR1.
|
||||
|
||||
Added counts of queries forwarded and queries answered
|
||||
locally (from the cache, /etc/hosts or config).
|
||||
|
||||
Fixed possible crash bug in DBus IPv6 code. Thanks to Matt
|
||||
Domsch and Jima.
|
||||
|
||||
Tighten checks for clashes between hosts-file and
|
||||
DHCP-derived names. Multiple addresses associated with a
|
||||
name in hosts-file no longer confuses the check.
|
||||
|
||||
Add --dhcp-no-override option to fix problems with some
|
||||
combinations of stage zero and stage one
|
||||
bootloaders. Thanks to Steve Alexander for the bug report.
|
||||
|
||||
Add --tftp-port-range option. Thanks to Daniel Mierswa for
|
||||
the suggestion.
|
||||
|
||||
Add --stop-dns-rebind option. Thanks to Collin Mulliner
|
||||
for the patch.
|
||||
|
||||
Added GPL version 3 as a license option.
|
||||
|
||||
Added --all-servers option. Thanks to Peter Naulls for the
|
||||
patch.
|
||||
|
||||
Extend source address mechanism so that the interface used
|
||||
to contact an upstream DNS server can be nailed
|
||||
down. Something like "--server=1.2.3.4@eth1" will force
|
||||
the use of eth1 for traffic to DNS-server 1.2.3.4. This
|
||||
facility is only available on Linux and Solaris. Thanks to
|
||||
Peter Naulls for prompting this.
|
||||
|
||||
Add --dhcp-optsfile option. Thanks to Carlos Carvalho for
|
||||
the suggestion.
|
||||
|
||||
Fixed failure to set source address for server connections
|
||||
when using TCP. Thanks to Simon Capper for finding this
|
||||
bug.
|
||||
|
||||
Refuse to give a DHCP client the address it asks for if
|
||||
the address range in question is not available to that
|
||||
particular host. Thanks to Cedric Duval for the bug
|
||||
report.
|
||||
|
||||
Changed behavior of DHCP server to always return total length of
|
||||
a new lease in DHCPOFFER, even if an existing lease
|
||||
exists. (It used to return the time remaining on the lease
|
||||
whne one existed.) This fixes problems with the Sony Ericsson
|
||||
K610i phone. Thanks to Hakon Stordahl for finding and
|
||||
fixing this.
|
||||
|
||||
Add DNSMASQ_INTERFACE to the environment of the
|
||||
lease-change script. Thanks to Nikos Mavrogiannopoulos for
|
||||
the patch.
|
||||
|
||||
Fixed broken --alias functionality. Thanks to Michael
|
||||
Meelis for the bug report.
|
||||
|
||||
Added French translation of the man page. Thank to Gildas
|
||||
Le Nadan for that.
|
||||
|
||||
Add --dhcp-match flag, to check for arbitrary options in
|
||||
DHCP messages from clients. This enables use of dnsmasq
|
||||
with gPXE. Thanks to Rance Hall for the suggestion.
|
||||
|
||||
Added --dhcp-broadcast, to force broadcast replies to DHCP
|
||||
clients which need them but are too dumb or too old to
|
||||
ask. Thanks to Bodo Bellut for the suggestion.
|
||||
|
||||
Disable path-MTU discovery on DHCP and TFTP sockets. This
|
||||
is never needed, and the presence of DF flags in the IP
|
||||
header confuses some broken PXE ROMS. Thanks again to Bodo
|
||||
Bellut for spotting this.
|
||||
|
||||
Fix problems with addresses which have multiple PTR
|
||||
records - all but one of these could get lost.
|
||||
|
||||
Fix bug with --address and ANY query type seeing REFUSED
|
||||
return code in replies. Thanks to Mike Wright for spotting
|
||||
the problem.
|
||||
|
||||
Update Spanish translation. Thanks to Chris Chatham.
|
||||
|
||||
Add --neg-ttl option.
|
||||
|
||||
Add warnings about the bad effects of --filterwin2k on
|
||||
SIP, XMPP and Google-talk to the example config file.
|
||||
|
||||
Fix va_list abuse in log.c. This fixes crashes on powerpc
|
||||
when debug mode is set. Thanks to Cedric Duval for the
|
||||
patch.
|
||||
|
||||
version 2.42
|
||||
Define _GNU_SOURCE to avoid problems with later glibc
|
||||
headers. Thanks to Jima for spotting the problem.
|
||||
|
||||
Add --dhcp-alternate-port option. Thanks to Jan Psota for
|
||||
the suggestion.
|
||||
|
||||
Fix typo in code which is only used on BSD, when Dbus and
|
||||
IPv6 support is enabled. Thanks to Roy Marples.
|
||||
|
||||
Updated Polish translations - thank to Jan Psota.
|
||||
|
||||
Fix OS detection logic to cope with GNU/FreeBSD.
|
||||
|
||||
Fix unitialised variable in DBus code - thanks to Roy
|
||||
Marples.
|
||||
|
||||
Fix network enumeration code to work on later NetBSD -
|
||||
thanks to Roy Marples.
|
||||
|
||||
Provide --dhcp-bridge on all BSD variants.
|
||||
|
||||
Define _LARGEFILE_SOURCE which removes an arbitrary 2GB
|
||||
limit on logfiles. Thanks to Paul Chambers for spotting
|
||||
the problem.
|
||||
|
||||
Fix RFC3046 agent-id echo code, broken for many
|
||||
releases. Thanks to Jeremy Laine for spotting the problem
|
||||
and providing a patch.
|
||||
|
||||
Added Solaris 10 service manifest from David Connelly in
|
||||
contrib/Solaris10
|
||||
|
||||
Add --dhcp-scriptuser option.
|
||||
|
||||
Support new capability interface on suitable Linux
|
||||
kernels, removes "legacy support in use" messages. Thanks
|
||||
to Jorge Bastos for pointing this out.
|
||||
|
||||
Fix subtle bug in cache code which could cause dnsmasq to
|
||||
lock spinning CPU in rare circumstances. Thanks to Alex
|
||||
Chekholko for bug reports and help debugging.
|
||||
|
||||
Support netascii transfer mode for TFTP.
|
||||
|
||||
|
||||
version 2.43
|
||||
Updated Polish translation. Thanks to Jan Psota.
|
||||
|
||||
Flag errors when configuration options are repeated
|
||||
illegally.
|
||||
|
||||
Further tweaks for GNU/kFreeBSD
|
||||
|
||||
Add --no-wrap to msgmerge call - provides nicer .po file
|
||||
format.
|
||||
|
||||
Honour lease-time spec in dhcp-host lines even for
|
||||
BOOTP. The user is assumed to known what they are doing in
|
||||
this case. (Hosts without the time spec still get infinite
|
||||
leases for BOOTP, over-riding the default in the
|
||||
dhcp-range.) Thanks to Peter Katzmann for uncovering this.
|
||||
|
||||
Fix problem matching relay-agent ids. Thanks to Michael
|
||||
Rack for the bug report.
|
||||
|
||||
Add --naptr-record option. Suggestion from Johan
|
||||
Bergquist.
|
||||
|
||||
Implement RFC 5107 server-id-override DHCP relay agent
|
||||
option.
|
||||
|
||||
Apply patches from Stefan Kruger for compilation on
|
||||
Solaris 10 under Sun studio.
|
||||
|
||||
Yet more tweaking of Linux capability code, to suppress
|
||||
pointless wingeing from kernel 2.6.25 and above.
|
||||
|
||||
Improve error checking during startup. Previously, some
|
||||
errors which occurred during startup would be worked
|
||||
around, with dnsmasq still starting up. Some were logged,
|
||||
some silent. Now, they all cause a fatal error and dnsmasq
|
||||
terminates with a non-zero exit code. The errors are those
|
||||
associated with changing uid and gid, setting process
|
||||
capabilities and writing the pidfile. Thanks to Uwe
|
||||
Gansert and the Suse security team for pointing out
|
||||
this improvement, and Bill Reimers for good implementation
|
||||
suggestions.
|
||||
|
||||
Provide NO_LARGEFILE compile option to switch off largefile
|
||||
support when compiling against versions of uclibc which
|
||||
don't support it. Thanks to Stephane Billiart for the patch.
|
||||
|
||||
Implement random source ports for interactions with
|
||||
upstream nameservers. New spoofing attacks have been found
|
||||
against nameservers which do not do this, though it is not
|
||||
clear if dnsmasq is vulnerable, since to doesn't implement
|
||||
recursion. By default dnsmasq will now use a different
|
||||
source port (and socket) for each query it sends
|
||||
upstream. This behaviour can suppressed using the
|
||||
--query-port option, and the old default behaviour
|
||||
restored using --query-port=0. Explicit source-port
|
||||
specifications in --server configs are still honoured.
|
||||
|
||||
Replace the random number generator, for better
|
||||
security. On most BSD systems, dnsmasq uses the
|
||||
arc4random() RNG, which is secure, but on other platforms,
|
||||
it relied on the C-library RNG, which may be
|
||||
guessable and therefore allow spoofing. This release
|
||||
replaces the libc RNG with the SURF RNG, from Daniel
|
||||
J. Berstein's DJBDNS package.
|
||||
|
||||
Don't attempt to change user or group or set capabilities
|
||||
if dnsmasq is run as a non-root user. Without this, the
|
||||
change from soft to hard errors when these fail causes
|
||||
problems for non-root daemons listening on high
|
||||
ports. Thanks to Patrick McLean for spotting this.
|
||||
|
||||
Updated French translation. Thanks to Gildas Le Nadan.
|
||||
|
||||
|
||||
674
COPYING-v3
Normal file
674
COPYING-v3
Normal file
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
32
FAQ
32
FAQ
@@ -1,7 +1,7 @@
|
||||
Q: Why does dnsmasq open UDP ports >1024 as well as port 53.
|
||||
Is this a security problem/trojan/backdoor?
|
||||
|
||||
A: The high ports that dnsmasq opens is for replies from the upstream
|
||||
A: The high ports that dnsmasq opens are for replies from the upstream
|
||||
nameserver(s). Queries from dnsmasq to upstream nameservers are sent
|
||||
from these ports and replies received to them. The reason for doing this is
|
||||
that most firewall setups block incoming packets _to_ port 53, in order
|
||||
@@ -39,10 +39,9 @@ A: They are negative entries: that's what the N flag means. Dnsmasq asked
|
||||
|
||||
Q: Will dnsmasq compile/run on non-Linux systems?
|
||||
|
||||
A: Yes, there is explicit support for *BSD and MacOS X. There are
|
||||
start-up scripts for MacOS X Tiger and Panther in /contrib. Earlier
|
||||
dnsmasq releases ran under Solaris, but that capability has
|
||||
rotted. Dnsmasq will link with uclibc to provide small
|
||||
A: Yes, there is explicit support for *BSD and MacOS X and Solaris.
|
||||
There are start-up scripts for MacOS X Tiger and Panther
|
||||
in /contrib. Dnsmasq will link with uclibc to provide small
|
||||
binaries suitable for use in embedded systems such as
|
||||
routers. (There's special code to support machines with flash
|
||||
filesystems and no battery-backed RTC.)
|
||||
@@ -50,7 +49,7 @@ A: Yes, there is explicit support for *BSD and MacOS X. There are
|
||||
ports and building dnsmasq with "make MAKE=gmake"
|
||||
For other systems, try altering the settings in config.h.
|
||||
|
||||
Q: My companies' nameserver knows about some names which aren't in the
|
||||
Q: My company's nameserver knows about some names which aren't in the
|
||||
public DNS. Even though I put it first in /etc/resolv.conf, it
|
||||
dosen't work: dnsmasq seems not to use the nameservers in the order
|
||||
given. What am I doing wrong?
|
||||
@@ -227,7 +226,7 @@ A: What is happening is this: The boot process sends a DHCP
|
||||
Q: What network types are supported by the DHCP server?
|
||||
|
||||
A: Ethernet (and 802.11 wireless) are supported on all platforms. On
|
||||
Linux Token Ring is also supported.
|
||||
Linux all network types (including FireWire) are supported.
|
||||
|
||||
Q: What is this strange "bind-interface" option?
|
||||
|
||||
@@ -380,12 +379,20 @@ A: This a variant on the iptables problem. Explicit details on how to
|
||||
http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2005q3/000431.html
|
||||
|
||||
|
||||
Q: Dnsmasq logs "running as root because setting capabilities failed"
|
||||
when it starts up. Why did that happen and what can do to fix it?
|
||||
Q: I'm using dnsmasq on a machine with the shorewall firewall, and
|
||||
DHCP doesn't work. What's the problem?
|
||||
|
||||
A: This a variant on the iptables problem. Explicit details on how to
|
||||
proceed can be found at
|
||||
http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2007q4/001764.html
|
||||
|
||||
|
||||
Q: Dnsmasq fails to start up with a message about capabilities.
|
||||
Why did that happen and what can do to fix it?
|
||||
|
||||
A: Change your kernel configuration: either deselect CONFIG_SECURITY
|
||||
_or_ select CONFIG_SECURITY_CAPABILITIES.
|
||||
|
||||
_or_ select CONFIG_SECURITY_CAPABILITIES. Alternatively, you can
|
||||
remove the need to set capabilities by running dnsmasq as root.
|
||||
|
||||
Q: Where can I get .rpms Suitable for Suse?
|
||||
|
||||
@@ -429,9 +436,6 @@ A: In almost all cases: none. If you have the normal arrangement with
|
||||
chain reaction runaway will occur. To avoid this, use syslog-ng
|
||||
and turn on syslog-ng's dns-cache function.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
60
Makefile
60
Makefile
@@ -1,18 +1,47 @@
|
||||
PREFIX ?= /usr/local
|
||||
BINDIR ?= ${PREFIX}/sbin
|
||||
MANDIR ?= ${PREFIX}/share/man
|
||||
LOCALEDIR ?= ${PREFIX}/share/locale
|
||||
# dnsmasq is Copyright (c) 2000-2007 Simon Kelley
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; version 2 dated June, 1991, or
|
||||
# (at your option) version 3 dated 29 June, 2007.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
PREFIX = /usr/local
|
||||
BINDIR = ${PREFIX}/sbin
|
||||
MANDIR = ${PREFIX}/share/man
|
||||
LOCALEDIR = ${PREFIX}/share/locale
|
||||
|
||||
SRC = src
|
||||
PO = po
|
||||
MAN = man
|
||||
|
||||
CFLAGS?= -O2
|
||||
PKG_CONFIG = pkg-config
|
||||
AWK = nawk
|
||||
INSTALL = install
|
||||
|
||||
DBUS_MINOR=" `echo $(COPTS) | ../bld/pkg-wrapper $(PKG_CONFIG) --modversion dbus-1 | $(AWK) -F . -- '{ if ($$(NF-1)) print \"-DDBUS_MINOR=\"$$(NF-1) }'`"
|
||||
DBUS_CFLAGS="`echo $(COPTS) | ../bld/pkg-wrapper $(PKG_CONFIG) --cflags dbus-1`"
|
||||
DBUS_LIBS=" `echo $(COPTS) | ../bld/pkg-wrapper $(PKG_CONFIG) --libs dbus-1`"
|
||||
SUNOS_VER=" `if uname | grep SunOS 2>&1 >/dev/null; then uname -r | $(AWK) -F . -- '{ print \"-DSUNOS_VER=\"$$2 }'; fi`"
|
||||
SUNOS_LIBS=" `if uname | grep SunOS 2>&1 >/dev/null; then echo -lsocket -lnsl -lposix4; fi `"
|
||||
|
||||
all : dnsmasq
|
||||
|
||||
dnsmasq :
|
||||
$(MAKE) I18N=-DNO_GETTEXT -f ../bld/Makefile -C $(SRC) dnsmasq
|
||||
cd $(SRC) && $(MAKE) \
|
||||
DBUS_MINOR=$(DBUS_MINOR) \
|
||||
DBUS_CFLAGS=$(DBUS_CFLAGS) \
|
||||
DBUS_LIBS=$(DBUS_LIBS) \
|
||||
SUNOS_LIBS=$(SUNOS_LIBS) \
|
||||
SUNOS_VER=$(SUNOS_VER) \
|
||||
-f ../bld/Makefile dnsmasq
|
||||
|
||||
clean :
|
||||
rm -f *~ $(SRC)/*.mo contrib/*/*~ */*~ $(SRC)/*.pot
|
||||
@@ -21,14 +50,21 @@ clean :
|
||||
install : all install-common
|
||||
|
||||
install-common :
|
||||
install -d $(DESTDIR)$(BINDIR) -d $(DESTDIR)$(MANDIR)/man8
|
||||
install -m 644 $(MAN)/dnsmasq.8 $(DESTDIR)$(MANDIR)/man8
|
||||
install -m 755 $(SRC)/dnsmasq $(DESTDIR)$(BINDIR)
|
||||
$(INSTALL) -d $(DESTDIR)$(BINDIR) -d $(DESTDIR)$(MANDIR)/man8
|
||||
$(INSTALL) -m 644 $(MAN)/dnsmasq.8 $(DESTDIR)$(MANDIR)/man8
|
||||
$(INSTALL) -m 755 $(SRC)/dnsmasq $(DESTDIR)$(BINDIR)
|
||||
|
||||
all-i18n :
|
||||
$(MAKE) I18N=-DLOCALEDIR='\"$(LOCALEDIR)\"' -f ../bld/Makefile -C $(SRC) dnsmasq
|
||||
cd $(SRC) && $(MAKE) \
|
||||
I18N=-DLOCALEDIR='\"$(LOCALEDIR)\"' \
|
||||
DBUS_MINOR=$(DBUS_MINOR) \
|
||||
DBUS_CFLAGS=$(DBUS_CFLAGS) \
|
||||
DBUS_LIBS=$(DBUS_LIBS) \
|
||||
SUNOS_LIBS=$(SUNOS_LIBS) \
|
||||
SUNOS_VER=$(SUNOS_VER) \
|
||||
-f ../bld/Makefile dnsmasq
|
||||
cd $(PO); for f in *.po; do \
|
||||
$(MAKE) -f ../bld/Makefile -C ../$(SRC) $${f%.po}.mo; \
|
||||
cd ../$(SRC) && $(MAKE) -f ../bld/Makefile $${f%.po}.mo; \
|
||||
done
|
||||
|
||||
install-i18n : all-i18n install-common
|
||||
@@ -38,7 +74,7 @@ install-i18n : all-i18n install-common
|
||||
merge :
|
||||
$(MAKE) I18N=-DLOCALEDIR='\"$(LOCALEDIR)\"' -f ../bld/Makefile -C $(SRC) dnsmasq.pot
|
||||
cd $(PO); for f in *.po; do \
|
||||
msgmerge -U $$f ../$(SRC)/dnsmasq.pot; \
|
||||
msgmerge --no-wrap -U $$f ../$(SRC)/dnsmasq.pot; \
|
||||
done
|
||||
|
||||
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
CFLAGS ?= -O2
|
||||
PKG_CONFIG ?= pkg-config
|
||||
|
||||
CFLAGS = -Wall -W -O2
|
||||
|
||||
OBJS = cache.o rfc1035.o util.o option.o forward.o isc.o network.o \
|
||||
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
|
||||
helper.o tftp.o log.o
|
||||
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) $(COPTS) $(I18N) `echo $(COPTS) | ../bld/pkg-wrapper $(PKG_CONFIG) --cflags dbus-1` $(RPM_OPT_FLAGS) -Wall -W -c $<
|
||||
$(CC) $(CFLAGS) $(COPTS) $(DBUS_MINOR) $(I18N) $(DBUS_CFLAGS) $(SUNOS_VER) $(RPM_OPT_FLAGS) -c $<
|
||||
|
||||
dnsmasq : $(OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $(OBJS) `echo $(COPTS) | ../bld/pkg-wrapper $(PKG_CONFIG) --libs dbus-1` $(LIBS)
|
||||
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(DBUS_LIBS) $(SUNOS_LIBS) $(LIBS)
|
||||
|
||||
dnsmasq.pot : $(OBJS:.o=.c) dnsmasq.h config.h
|
||||
xgettext -d dnsmasq --foreign-user --keyword=_ -o dnsmasq.pot -i $(OBJS:.o=.c)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
for f in *; do
|
||||
if [ -d $f ]; then
|
||||
install -d $1/$f/man8
|
||||
install -m 755 -d $1/$f/man8
|
||||
install -m 644 $f/dnsmasq.8 $1/$f/man8
|
||||
echo installing $1/$f/man8/dnsmasq.8
|
||||
fi
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
for f in *.mo; do
|
||||
install -d $1/${f%.mo}/LC_MESSAGES
|
||||
install -m 755 -d $1/${f%.mo}/LC_MESSAGES
|
||||
install -m 644 $f $1/${f%.mo}/LC_MESSAGES/dnsmasq.mo
|
||||
echo installing $1/${f%.mo}/LC_MESSAGES/dnsmasq.mo
|
||||
done
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
if grep -q "^\#.*define.*HAVE_DBUS" config.h || grep -q HAVE_DBUS ; then
|
||||
if grep "^\#.*define.*HAVE_DBUS" config.h 2>&1 >/dev/null || \
|
||||
grep HAVE_DBUS 2>&1 >/dev/null ; then
|
||||
exec $*
|
||||
fi
|
||||
|
||||
|
||||
28
contrib/Solaris10/README
Normal file
28
contrib/Solaris10/README
Normal file
@@ -0,0 +1,28 @@
|
||||
From: David Connelly <dconnelly@gmail.com>
|
||||
Date: Mon, Apr 7, 2008 at 3:31 AM
|
||||
Subject: Solaris 10 service manifest
|
||||
To: dnsmasq-discuss@lists.thekelleys.org.uk
|
||||
|
||||
|
||||
I've found dnsmasq much easier to set up on my home server running Solaris
|
||||
10 than the stock dhcp/dns server, which is probably overkill anyway for my
|
||||
simple home network needs. Since Solaris now uses SMF (Service Management
|
||||
Facility) to manage services I thought I'd create a simple service manifest
|
||||
for the dnsmasq service. The manifest currently assumes that dnsmasq has
|
||||
been installed in '/usr/local/sbin/dnsmasq' and the configuration file in
|
||||
'/usr/local/etc/dnsmasq.conf', so you may have to adjust these paths for
|
||||
your local installation. Here are the steps I followed to install and enable
|
||||
the dnsmasq service:
|
||||
# svccfg import dnsmasq.xml
|
||||
# svcadm enable dnsmasq
|
||||
|
||||
To confirm that the service is enabled and online:
|
||||
|
||||
# svcs -l dnsmasq
|
||||
|
||||
I've just started learning about SMF so if anyone has any
|
||||
corrections/feedback they are more than welcome.
|
||||
|
||||
Thanks,
|
||||
David
|
||||
|
||||
65
contrib/Solaris10/dnsmasq.xml
Normal file
65
contrib/Solaris10/dnsmasq.xml
Normal file
@@ -0,0 +1,65 @@
|
||||
<?xml version='1.0'?>
|
||||
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
|
||||
|
||||
<!-- Service manifest for dnsmasq -->
|
||||
|
||||
<service_bundle type='manifest' name='dnsmasq'>
|
||||
<service name='network/dnsmasq' type='service' version='1'>
|
||||
|
||||
<create_default_instance enabled='false'/>
|
||||
<single_instance/>
|
||||
|
||||
<dependency name='multi-user'
|
||||
grouping='require_all'
|
||||
restart_on='refresh'
|
||||
type='service'>
|
||||
<service_fmri value='svc:/milestone/multi-user'/>
|
||||
</dependency>
|
||||
|
||||
<dependency name='config'
|
||||
grouping='require_all'
|
||||
restart_on='restart'
|
||||
type='path'>
|
||||
<service_fmri value='file:///usr/local/etc/dnsmasq.conf'/>
|
||||
</dependency>
|
||||
|
||||
<dependent name='dnsmasq_multi-user-server'
|
||||
grouping='optional_all'
|
||||
restart_on='none'>
|
||||
<service_fmri value='svc:/milestone/multi-user-server' />
|
||||
</dependent>
|
||||
|
||||
<exec_method type='method' name='start'
|
||||
exec='/usr/local/sbin/dnsmasq -C /usr/local/etc/dnsmasq.conf'
|
||||
timeout_seconds='60' >
|
||||
<method_context>
|
||||
<method_credential user='root' group='root' privileges='all'/>
|
||||
</method_context>
|
||||
</exec_method>
|
||||
|
||||
<exec_method type='method'
|
||||
name='stop'
|
||||
exec=':kill'
|
||||
timeout_seconds='60'/>
|
||||
|
||||
<exec_method type='method'
|
||||
name='refresh'
|
||||
exec=':kill -HUP'
|
||||
timeout_seconds='60' />
|
||||
|
||||
<template>
|
||||
<common_name>
|
||||
<loctext xml:lang='C'>dnsmasq server</loctext>
|
||||
</common_name>
|
||||
<description>
|
||||
<loctext xml:lang='C'>
|
||||
dnsmasq - A lightweight DHCP and caching DNS server.
|
||||
</loctext>
|
||||
</description>
|
||||
<documentation>
|
||||
<manpage title='dnsmasq' section='8' manpath='/usr/local/man'/>
|
||||
</documentation>
|
||||
</template>
|
||||
|
||||
</service>
|
||||
</service_bundle>
|
||||
@@ -19,7 +19,7 @@
|
||||
# Uncomment this to filter useless windows-originated DNS requests
|
||||
# which can trigger dial-on-demand links needlessly.
|
||||
# Note that (amongst other things) this blocks all SRV requests,
|
||||
# so don't use it if you use eg Kerberos.
|
||||
# so don't use it if you use eg Kerberos, SIP, XMMP or Google-talk.
|
||||
# This option only affects forwarding, SRV records originating for
|
||||
# dnsmasq (via srv-host= lines) are not suppressed by it.
|
||||
#filterwin2k
|
||||
@@ -61,6 +61,18 @@
|
||||
# webserver.
|
||||
#address=/doubleclick.net/127.0.0.1
|
||||
|
||||
# --address (and --server) work with IPv6 addresses too.
|
||||
#address=/www.thekelleys.org.uk/fe80::20d:60ff:fe36:f83
|
||||
|
||||
# You can control how dnsmasq talks to a server: this forces
|
||||
# queries to 10.1.2.3 to be routed via eth1
|
||||
# --server=10.1.2.3@eth1
|
||||
|
||||
# and this sets the source (ie local) address used to talk to
|
||||
# 10.1.2.3 to 192.168.1.1 port 55 (there must be a interface with that
|
||||
# IP on the machine, obviously).
|
||||
# --server=10.1.2.3@192.168.1.1#55
|
||||
|
||||
# If you want dnsmasq to change uid and gid to something other
|
||||
# than the default, edit the following lines.
|
||||
#user=
|
||||
@@ -145,7 +157,7 @@
|
||||
# the name fred and IP address 192.168.0.60 and lease time 45 minutes
|
||||
#dhcp-host=11:22:33:44:55:66,fred,192.168.0.60,45m
|
||||
|
||||
# Give the machine which says it's name is "bert" IP address
|
||||
# Give the machine which says its name is "bert" IP address
|
||||
# 192.168.0.70 and an infinite lease
|
||||
#dhcp-host=bert,192.168.0.70,infinite
|
||||
|
||||
@@ -309,6 +321,13 @@
|
||||
# external one. (See below for how to enable the TFTP server.)
|
||||
#dhcp-boot=pxelinux.0
|
||||
|
||||
# Boot for Etherboot gPXE. The idea is to send two different
|
||||
# filenames, the first loads gPXE, and the second tells gPXE what to
|
||||
# load. The dhcp-match sets the gpxe tag for requests from gPXE.
|
||||
#dhcp-match=gpxe,175 # gPXE sends a 175 option.
|
||||
#dhcp-boot=net:#gpxe,undionly.kpxe
|
||||
#dhcp-boot=mybootimage
|
||||
|
||||
# Enable dnsmasq's built-in TFTP server
|
||||
#enable-tftp
|
||||
|
||||
|
||||
6
doc.html
6
doc.html
@@ -19,8 +19,8 @@ connection but would be a good choice for any smallish network (up to
|
||||
1000 clients is known to work) where low
|
||||
resource use and ease of configuration are important.
|
||||
<P>
|
||||
Supported platforms include Linux (with glibc and uclibc), *BSD and
|
||||
Mac OS X.
|
||||
Supported platforms include Linux (with glibc and uclibc), *BSD,
|
||||
Solaris and Mac OS X.
|
||||
Dnsmasq is included in at least the following Linux distributions:
|
||||
Gentoo, Debian, Slackware, Suse, Fedora,
|
||||
Smoothwall, IP-Cop, floppyfw, Firebox, LEAF, Freesco, fli4l,
|
||||
@@ -59,7 +59,7 @@ improving performance (especially on modem connections).
|
||||
</LI>
|
||||
<LI>
|
||||
Dnsmasq can be configured to automatically pick up the addresses of
|
||||
it's upstream nameservers from ppp or dhcp configuration. It will
|
||||
its upstream nameservers from ppp or dhcp configuration. It will
|
||||
automatically reload this information if it changes. This facility
|
||||
will be of particular interest to maintainers of Linux firewall
|
||||
distributions since it allows dns configuration to be made automatic.
|
||||
|
||||
152
man/dnsmasq.8
152
man/dnsmasq.8
@@ -52,6 +52,14 @@ time-to-live (in seconds) to be given for these replies. This will
|
||||
reduce the load on the server at the expense of clients using stale
|
||||
data under some circumstances.
|
||||
.TP
|
||||
.B --neg-ttl=<time>
|
||||
Negative replies from upstream servers normally contain time-to-live
|
||||
information in SOA records which dnsmasq uses for caching. If the
|
||||
replies from upstream servers omit this information, dnsmasq does not
|
||||
cache the reply. This option gives a default value for time-to-live
|
||||
(in seconds) which dnsmasq uses to cache negative replies even in
|
||||
the absence of an SOA record.
|
||||
.TP
|
||||
.B \-k, --keep-in-foreground
|
||||
Do not go into the background at startup but otherwise run as
|
||||
normal. This is intended for use when dnsmasq is run under daemontools
|
||||
@@ -69,7 +77,7 @@ Log the results of DNS queries handled by dnsmasq. Enable a full cache dump on r
|
||||
.B \-8, --log-facility=<facility>
|
||||
Set the facility to which dnsmasq will send syslog entries, this
|
||||
defaults to DAEMON, and to LOCAL0 when debug mode is in operation. If
|
||||
the facilty given contains at least one '/' character, it is taken to
|
||||
the facility given contains at least one '/' character, it is taken to
|
||||
be a filename, and dnsmasq logs to the given file, instead of
|
||||
syslog. (Errors whilst reading configuration will still go to syslog,
|
||||
but all output from a successful startup, and all output whilst
|
||||
@@ -105,8 +113,8 @@ as. The defaults to "dip", if available, to facilitate access to
|
||||
Print the version number.
|
||||
.TP
|
||||
.B \-p, --port=<port>
|
||||
Listen on <port> instead of the standard DNS port (53). Useful mainly for
|
||||
debugging.
|
||||
Listen on <port> instead of the standard DNS port (53). Setting this
|
||||
to zero completely disables DNS function, leaving only DHCP and/or TFTP.
|
||||
.TP
|
||||
.B \-P, --edns-packet-max=<size>
|
||||
Specify the largest EDNS.0 UDP packet which is supported by the DNS
|
||||
@@ -114,9 +122,18 @@ forwarder. Defaults to 1280, which is the RFC2671-recommended maximum
|
||||
for ethernet.
|
||||
.TP
|
||||
.B \-Q, --query-port=<query_port>
|
||||
Send outbound DNS queries from, and listen for their replies on, the specific UDP port <query_port> instead of using one chosen at runtime. Useful to simplify your
|
||||
firewall rules; without this, your firewall would have to allow connections from outside DNS servers to a range of UDP ports, or dynamically adapt to the
|
||||
port being used by the current dnsmasq instance.
|
||||
Send outbound DNS queries from, and listen for their replies on, the
|
||||
specific UDP port <query_port> instead of using random ports. NOTE
|
||||
that using this option will make dnsmasq less secure against DNS
|
||||
spoofing attacks but it may be faster and use less resources. Setting this option
|
||||
to zero makes dnsmasq use a single port allocated to it by the
|
||||
OS: this was the default behaviour in versions prior to 2.43.
|
||||
.TP
|
||||
.B --min-port=<port>
|
||||
Do not use ports less than that given as source for outbound DNS
|
||||
queries. Dnsmasq picks random ports as source for outbound queries:
|
||||
when this option is given, the ports used will always to larger
|
||||
than that specified. Useful for systems behind firewalls.
|
||||
.TP
|
||||
.B \-i, --interface=<interface name>
|
||||
Listen only on the specified interface(s). Dnsmasq automatically adds
|
||||
@@ -236,10 +253,21 @@ been built with DBus support.
|
||||
.TP
|
||||
.B \-o, --strict-order
|
||||
By default, dnsmasq will send queries to any of the upstream servers
|
||||
it knows about and tries to favour servers to are known to
|
||||
it knows about and tries to favour servers that are known to
|
||||
be up. Setting this flag forces dnsmasq to try each query with each
|
||||
server strictly in the order they appear in /etc/resolv.conf
|
||||
.TP
|
||||
.B --all-servers
|
||||
By default, when dnsmasq has more than one upstream server available,
|
||||
it will send queries to just one server. Setting this flag forces
|
||||
dnsmasq to send all queries to all available servers. The reply from
|
||||
the server which answers first will be returned to the original requestor.
|
||||
.TP
|
||||
.B --stop-dns-rebind
|
||||
Reject (and log) addresses from upstream nameservers which are in the
|
||||
private IP ranges. This blocks an attack where a browser behind a
|
||||
firewall is used to probe machines on the local network.
|
||||
.TP
|
||||
.B \-n, --no-poll
|
||||
Don't poll /etc/resolv.conf for changes.
|
||||
.TP
|
||||
@@ -253,7 +281,7 @@ Tells dnsmasq to never forward queries for plain names, without dots
|
||||
or domain parts, to upstream nameservers. If the name is not known
|
||||
from /etc/hosts or DHCP then a "not found" answer is returned.
|
||||
.TP
|
||||
.B \-S, --local, --server=[/[<domain>]/[domain/]][<ipaddr>[#<port>][@<source>[#<port>]]]
|
||||
.B \-S, --local, --server=[/[<domain>]/[domain/]][<ipaddr>[#<port>][@<source-ip>|<interface>[#<port>]]
|
||||
Specify IP address of upstream servers directly. Setting this flag does
|
||||
not suppress reading of /etc/resolv.conf, use -R to do that. If one or
|
||||
more
|
||||
@@ -284,13 +312,18 @@ is a synonym for
|
||||
.B server
|
||||
to make configuration files clearer in this case.
|
||||
|
||||
The optional second IP address after the @ character tells
|
||||
dnsmasq how to set the source address of the queries to this
|
||||
nameserver. It should be an address belonging to the machine on which
|
||||
The optional string after the @ character tells
|
||||
dnsmasq how to set the source of the queries to this
|
||||
nameserver. It should be an ip-address, which should belong to the machine on which
|
||||
dnsmasq is running otherwise this server line will be logged and then
|
||||
ignored. The query-port flag is ignored for any servers which have a
|
||||
ignored, or an interface name. If an interface name is given, then
|
||||
queries to the server will be forced via that interface; if an
|
||||
ip-address is given then the source address of the queries will be set
|
||||
to that address.
|
||||
The query-port flag is ignored for any servers which have a
|
||||
source address specified but the port may be specified directly as
|
||||
part of the source address.
|
||||
part of the source address. Forcing queries to an interface is not
|
||||
implemented on all platforms supported by dnsmasq.
|
||||
.TP
|
||||
.B \-A, --address=/<domain>/[domain/]<ipaddr>
|
||||
Specify an IP address to return for any host in the given domains.
|
||||
@@ -349,12 +382,15 @@ so any number may be included, split by commas.
|
||||
.B --ptr-record=<name>[,<target>]
|
||||
Return a PTR DNS record.
|
||||
.TP
|
||||
.B --naptr-record=<name>,<order>,<preference>,<flags>,<service>,<regexp>[,<replacement>]
|
||||
Return an NAPTR DNS record, as specified in RFC3403.
|
||||
.TP
|
||||
.B --interface-name=<name>,<interface>
|
||||
Return a DNS record associating the name with the primary address on
|
||||
the given interface. This flag specifies an A record for the given
|
||||
name in the same way as an /etc/hosts line, except that the address is
|
||||
not constant, but taken from the given interface. If the interface is
|
||||
down, not configured or non-existant, an empty record is returned. The
|
||||
down, not configured or non-existent, an empty record is returned. The
|
||||
matching PTR record is also created, mapping the interface address to
|
||||
the name. More than one name may be associated with an interface
|
||||
address by repeating the flag; in that case the first instance is used
|
||||
@@ -381,7 +417,8 @@ in
|
||||
.B dhcp-host
|
||||
options. If the lease time is given, then leases
|
||||
will be given for that length of time. The lease time is in seconds,
|
||||
or minutes (eg 45m) or hours (eg 1h) or the literal "infinite". This
|
||||
or minutes (eg 45m) or hours (eg 1h) or the literal "infinite". The
|
||||
minimum lease time is two minutes. This
|
||||
option may be repeated, with different addresses, to enable DHCP
|
||||
service to more than one network. For directly connected networks (ie,
|
||||
networks on which the machine running dnsmasq has an interface) the
|
||||
@@ -467,6 +504,11 @@ information about one host per line. The format of a line is the same
|
||||
as text to the right of '=' in --dhcp-host. The advantage of storing DHCP host information
|
||||
in this file is that it can be changed without re-starting dnsmasq:
|
||||
the file will be re-read when dnsmasq receives SIGHUP.
|
||||
.TP
|
||||
.B --dhcp-optsfile=<file>
|
||||
Read DHCP option information from the specified file. The advantage of
|
||||
using this option is the same as for --dhcp-hostsfile: the
|
||||
dhcp-optsfile will be re-read when dnsmasq receives SIGHUP.
|
||||
.TP
|
||||
.B \-Z, --read-ethers
|
||||
Read /etc/ethers for information about hosts for the DHCP server. The
|
||||
@@ -547,6 +589,14 @@ except that the option will always be sent, even if the client does
|
||||
not ask for it in the parameter request list. This is sometimes
|
||||
needed, for example when sending options to PXELinux.
|
||||
.TP
|
||||
.B --dhcp-no-override
|
||||
Disable re-use of the DHCP servername and filename fields as extra
|
||||
option space. If it can, dnsmasq moves the boot server and filename
|
||||
information (from dhcp-boot) out of their dedicated fields into
|
||||
DHCP options. This make extra space available in the DHCP packet for
|
||||
options but can, rarely, confuse old or broken clients. This flag
|
||||
forces "simple and safe" behaviour to avoid problems in such a case.
|
||||
.TP
|
||||
.B \-U, --dhcp-vendorclass=<network-id>,<vendor-class>
|
||||
Map from a vendor-class string to a network id tag. Most DHCP clients provide a
|
||||
"vendor class" which represents, in some sense, the type of host. This option
|
||||
@@ -582,7 +632,12 @@ simple string. If an exact match is achieved between the circuit or
|
||||
agent ID and one provided by a relay agent, the network-id tag is set.
|
||||
.TP
|
||||
.B --dhcp-subscrid=<network-id>,<subscriber-id>
|
||||
Map from RFC3993 subscriber-d relay agent options to network-id tags.
|
||||
Map from RFC3993 subscriber-id relay agent options to network-id tags.
|
||||
.TP
|
||||
.B --dhcp-match=<network-id>,<option number>
|
||||
Set the network-id tag if the client sends a DHCP option of the given
|
||||
number. This can be used to identify particular clients which send
|
||||
information using private option numbers.
|
||||
.TP
|
||||
.B \-J, --dhcp-ignore=<network-id>[,<network-id>]
|
||||
When all the given network-ids match the set of network-ids derived
|
||||
@@ -592,12 +647,19 @@ not allocate it a DHCP lease.
|
||||
.B --dhcp-ignore-names[=<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 any hostname
|
||||
provided by the host. Note that, unlike dhcp-ignore, it is permissable
|
||||
provided by the host. Note that, unlike dhcp-ignore, it is permissible
|
||||
to supply no netid tags, in which case DHCP-client supplied hostnames
|
||||
are always ignored, and DHCP hosts are added to the DNS using only
|
||||
dhcp-host configuration in dnsmasq and the contents of /etc/hosts and
|
||||
/etc/ethers.
|
||||
.TP
|
||||
.B --dhcp-broadcast=<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, always use broadcast to
|
||||
communicate with the host when it is unconfigured. Most DHCP clients which
|
||||
need broadcast replies set a flag in their requests so that this
|
||||
happens automatically, some old BOOTP clients do not.
|
||||
.TP
|
||||
.B \-M, --dhcp-boot=[net:<network-id>,]<filename>,[<servername>[,<server address>]]
|
||||
Set BOOTP options to be returned by the DHCP server. Server name and
|
||||
address are optional: if not provided, the name is left empty, and the
|
||||
@@ -621,7 +683,15 @@ It changes the behaviour from strict RFC compliance so that DHCP requests on
|
||||
unknown leases from unknown hosts are not ignored. This allows new hosts
|
||||
to get a lease without a tedious timeout under all circumstances. It also
|
||||
allows dnsmasq to rebuild its lease database without each client needing to
|
||||
reaquire a lease, if the database is lost.
|
||||
reacquire a lease, if the database is lost.
|
||||
.TP
|
||||
.B --dhcp-alternate-port[=<server port>[,<client port>]]
|
||||
Change the ports used for DHCP from the default. If this option is
|
||||
given alone, without arguments, it changes the ports used for DHCP
|
||||
from 67 and 68 to 1067 and 1068. If a single argument is given, that
|
||||
port number is used for the server and the port number plus one used
|
||||
for the client. Finally, two port numbers allows arbitrary
|
||||
specification of both server and client ports for DHCP.
|
||||
.TP
|
||||
.B \-3, --bootp-dynamic
|
||||
Enable dynamic allocation of IP addresses to BOOTP clients. Use this
|
||||
@@ -677,8 +747,10 @@ always stored in DNSMASQ_TIME_REMAINING.
|
||||
If a lease used to have a hostname, which is
|
||||
removed, an "old" event is generated with the new state of the lease,
|
||||
ie no name, and the former name is provided in the environment
|
||||
variable DNSMASQ_OLD_HOSTNAME.
|
||||
All file decriptors are
|
||||
variable DNSMASQ_OLD_HOSTNAME. DNSMASQ_INTERFACE stores the name of
|
||||
the interface on which the request arrived; this is not set for "old"
|
||||
actions when dnsmasq restarts.
|
||||
All file descriptors are
|
||||
closed except stdin, stdout and stderr which are open to /dev/null
|
||||
(except in debug mode).
|
||||
The script is not invoked concurrently: if subsequent lease
|
||||
@@ -688,7 +760,10 @@ all existing leases as they are read from the lease file. Expired
|
||||
leases will be called with "del" and others with "old". <path>
|
||||
must be an absolute pathname, no PATH search occurs. When dnsmasq
|
||||
receives a HUP signal, the script will be invoked for existing leases
|
||||
with an "old " event.
|
||||
with an "old " event.
|
||||
.TP
|
||||
.B --dhcp-scriptuser
|
||||
Specify the user as which to run the lease-change script. This defaults to root, but can be changed to another user using this flag.
|
||||
.TP
|
||||
.B \-9, --leasefile-ro
|
||||
Completely suppress use of the lease database file. The file will not
|
||||
@@ -707,7 +782,7 @@ to the client-id and lease length and expiry time.
|
||||
.B --bridge-interface=<interface>,<alias>[,<alias>]
|
||||
Treat DHCP request packets arriving at any of the <alias> interfaces
|
||||
as if they had arrived at <interface>. This option is only available
|
||||
on FreeBSD and Dragonfly BSD, and is necessary when using "old style" bridging, since
|
||||
on BSD platforms, and is necessary when using "old style" bridging, since
|
||||
packets arrive at tap interfaces which don't have an IP address.
|
||||
.TP
|
||||
.B \-s, --domain=<domain>
|
||||
@@ -732,8 +807,8 @@ in /etc/resolv.conf (or equivalent).
|
||||
.TP
|
||||
.B --enable-tftp
|
||||
Enable the TFTP server function. This is deliberately limited to that
|
||||
needed to net-boot a client: Only reading is allowed, and only in
|
||||
binary/octet mode. The tsize and blksize extensions are supported.
|
||||
needed to net-boot a client. Only reading is allowed; the tsize and
|
||||
blksize extensions are supported (tsize is only supported in octet mode).
|
||||
.TP
|
||||
.B --tftp-root=<directory>
|
||||
Look for files to transfer using TFTP relative to the given
|
||||
@@ -768,12 +843,23 @@ one file descriptor for each concurrent TFTP connection and one
|
||||
file descriptor per unique file (plus a few others). So serving the
|
||||
same file simultaneously to n clients will use require about n + 10 file
|
||||
descriptors, serving different files simultaneously to n clients will
|
||||
require about (2*n) + 10 descriptors.
|
||||
require about (2*n) + 10 descriptors. If
|
||||
.B --tftp-port-range
|
||||
is given, that can affect the number of concurrent connections.
|
||||
.TP
|
||||
.B --tftp-no-blocksize
|
||||
Stop the TFTP server from negotiating the "blocksize" option with a
|
||||
client. Some buggy clients request this option but then behave badly
|
||||
when it is granted.
|
||||
.TP
|
||||
.B --tftp-port-range=<start>,<end>
|
||||
A TFTP server listens on a well-known port (69) for connection initiation,
|
||||
but it also uses a dynamically-allocated port for each
|
||||
connection. Normally these are allocated by the OS, but this option
|
||||
specifies a range of ports for use by TFTP transfers. This can be
|
||||
useful when TFTP has to traverse a firewall. The start of the range
|
||||
cannot be lower than 1025 unless dnsmasq is running as root. The number
|
||||
of concurrent TFTP connections is limited by the size of the port range.
|
||||
.TP
|
||||
.B \-C, --conf-file=<file>
|
||||
Specify a different configuration file. The conf-file option is also allowed in
|
||||
@@ -800,8 +886,8 @@ in the OPTIONS section but without the leading "--". Lines starting with # are c
|
||||
options which may only be specified once, the configuration file overrides
|
||||
the command line. Quoting is allowed in a config file:
|
||||
between " quotes the special meanings of ,:. and # are removed and the
|
||||
following escapes are allowed: \\\\ \\" \\t \\a \\b \\r and \\n. The later
|
||||
corresponding to tab, bell, backspace, return and newline.
|
||||
following escapes are allowed: \\\\ \\" \\t \\e \\b \\r and \\n. The later
|
||||
corresponding to tab, escape, backspace, return and newline.
|
||||
.SH NOTES
|
||||
When it receives a SIGHUP,
|
||||
.B dnsmasq
|
||||
@@ -809,7 +895,7 @@ clears its cache and then re-loads
|
||||
.I /etc/hosts
|
||||
and
|
||||
.I /etc/ethers
|
||||
and any file given by --dhcp-hostsfile.
|
||||
and any file given by --dhcp-hostsfile, --dhcp-optsfile or --addn-hosts.
|
||||
The dhcp lease change script is called for all
|
||||
existing DHCP leases. If
|
||||
.B
|
||||
@@ -821,10 +907,12 @@ does NOT re-read the configuration file.
|
||||
.PP
|
||||
When it receives a SIGUSR1,
|
||||
.B dnsmasq
|
||||
writes cache statistics to the system log. It writes the cache size,
|
||||
writes statistics to the system log. It writes the cache size,
|
||||
the number of names which have had to removed from the cache before
|
||||
they expired in order to make room for new names and the total number
|
||||
of names that have been inserted into the cache. In
|
||||
of names that have been inserted into the cache. For each upstream
|
||||
server it gives the number of queries sent, and the number which
|
||||
resulted in an error. In
|
||||
.B --no-daemon
|
||||
mode or when full logging is enabled (-q), a complete dump of the
|
||||
contents of the cache is made.
|
||||
@@ -837,7 +925,7 @@ will close and reopen the log file. Note that during this operation,
|
||||
dnsmasq will not be running as root. When it first creates the logfile
|
||||
dnsmasq changes the ownership of the file to the non-root user it will run
|
||||
as. Logrotate should be configured to create a new log file with
|
||||
the ownership which matches the exising one before sending SIGUSR2.
|
||||
the ownership which matches the existing one before sending SIGUSR2.
|
||||
If TCP DNS queries are in progress, the old logfile will remain open in
|
||||
child processes which are handling TCP queries and may continue to be
|
||||
written. There is a limit of 150 seconds, after which all existing TCP
|
||||
@@ -962,7 +1050,7 @@ normally if backgrounding is not enabled.
|
||||
2 - A problem with network access occurred (address in use, attempt
|
||||
to use privileged ports without permission).
|
||||
.PP
|
||||
3 - A problem occured with a filesystem operation (missing
|
||||
3 - A problem occurred with a filesystem operation (missing
|
||||
file/directory, permissions).
|
||||
.PP
|
||||
4 - Memory allocation failure.
|
||||
|
||||
104
man/es/dnsmasq.8
104
man/es/dnsmasq.8
@@ -55,6 +55,15 @@ cierto tiempo de vida (en segundos) para estas respuestas. Esto
|
||||
reduce la carga sobre el servidor al costo de que los clientes
|
||||
usaran datos añejos bajo algunas circunstancias.
|
||||
.TP
|
||||
.B --neg-ttl=<tiempo>
|
||||
Respuestas negativas desde servidores upstream normalmente contienen
|
||||
información time-to-live (tiempo de vida) en expedientes SOA que
|
||||
dnsmasq usa para hacer caché. Si las respuestas de servidores upstream
|
||||
omiten esta información, dnsmasq no mete la respuesta en el caché.
|
||||
Esta opción brinda un valor predeterminado para el time-to-live que
|
||||
dnsmasq usa para meter respuestas en el caché aún en la ausencia de
|
||||
un expediente SOA.
|
||||
.TP
|
||||
.B \-k, --keep-in-foreground
|
||||
No ir hacia el fondo al iniciar, pero aparte de eso ejecutar como
|
||||
normal. La intención de esto es para cuando dnsmasq es ejecutado
|
||||
@@ -113,7 +122,8 @@ Mostrar el n
|
||||
.TP
|
||||
.B \-p, --port=<puerto>
|
||||
Escuchar en el puerto <puerto> en vez del puerto estándar DNS (53).
|
||||
Principalmente útil para debugging.
|
||||
Fijar esto a cero deshabilita completamente la función DNS, dejando
|
||||
solo DHCP y/o TFTP.
|
||||
.TP
|
||||
.B \-P, --edns-packet-max=<tamaño>
|
||||
Especificar el paquete UDP EDNS.0 más grande que es soportado por
|
||||
@@ -263,6 +273,18 @@ cuales sabe que est
|
||||
probar cada búsqueda con cada servidor estrictamente en el orden
|
||||
que aparecen en /etc/resolv.conf
|
||||
.TP
|
||||
.B --all-servers
|
||||
Por predeterminado, cuando dnsmasq tiene más de un servidor upstream
|
||||
disponible, enviará búsquedas a solo un servidor. Fijar esta opción
|
||||
forza a dnsmasq a enviar todas las búsquedas a todos los servidores
|
||||
disponibles. La respuesta del servidor que responda primero será
|
||||
devuelta al solicitante original.
|
||||
.TP
|
||||
.B --stop-dns-rebind
|
||||
Denegar (y bitacorear) direcciones de servidores upstream que están
|
||||
dentro de rangos IP privados. Esto bloquea un ataque donde un navegador
|
||||
detrás de un firewall es usado para analizar máquinas en la red local.
|
||||
.TP
|
||||
.B \-n, --no-poll
|
||||
No revisar periodicamente a /etc/resolv.conf en busca de cambios.
|
||||
.TP
|
||||
@@ -277,7 +299,7 @@ sin puntos o partes de dominios, a servidores upstream. Si el nombre
|
||||
no se conoce desde /etc/hosts o desde DHCP entonces una respuesta
|
||||
"no encontrado" es devuelta.
|
||||
.TP
|
||||
.B \-S, --local, --server=[/[<dominio>]/[dominio/]][<dirección IP>[#<puerto>][@<remitente>[#<puerto>]]]
|
||||
.B \-S, --local, --server=[/[<dominio>]/[dominio/]][<dirección IP>[#<puerto>][@<IP de remitente>|<interface>[#<puerto>]]
|
||||
Especificar la dirección IP de servidores upstream directamente. Fijar
|
||||
esta opción no suprime la lectura de /etc/resolv.conf, use -R para
|
||||
hacer eso. Si uno a más dominios opcionales son brindados, ese servidor
|
||||
@@ -307,14 +329,19 @@ es un sin
|
||||
.B server
|
||||
para hacer los archivos de configuración mas claros en este caso.
|
||||
|
||||
La segunda dirección IP opcional después del carácter @ le dice
|
||||
a dnsmasq como fijar la dirección de remitente de las búsquedas
|
||||
hacia este servidor DNS. Debe ser una dirección perteneciente a
|
||||
la máquina en la cual corre dnsmasq, de forma contraria esta
|
||||
línea de servidor será bitacoreada y después ignorada. La opción
|
||||
query-port es ignorada para cualquier servidores que tengan una
|
||||
dirección remitente especificada, pero el puerto puede ser
|
||||
especificado directamente como parte de la dirección remitente.
|
||||
El string opcional despues del carácter @ le dice a dnsmasq como fijar
|
||||
el remitente de las búsquedas hacia este servidor DNS. Debe ser una
|
||||
dirección IP, la cual debe ser perteneciente a la máquina en la cual
|
||||
corre dnsmasq, de forma contraria esta línea de servidor será bitacoreada
|
||||
y después ignorada, o un nombre de interface. Si un nombre de interface
|
||||
es brindado, entonces búsquedas hacia el servidor serán forzadas vía esa
|
||||
interface; si una dirección IP es brindada, entonces la dirección de
|
||||
remitente de las búsquedas será fijada a esa dirección.
|
||||
La etiqueta query-port es ignorada para cualquier servidores que tengan
|
||||
una dirección remitente especificada, pero el puerto puede ser
|
||||
especificado directamente como parte de la dirección remitente. Forzar
|
||||
búsquedas a una interface no está implementado en todas las plataformas
|
||||
soportadas por dnsmasq.
|
||||
.TP
|
||||
.B \-A, --address=/<dominio>/[dominio/]<dirección IP>
|
||||
Especificar una dirección IP para retornar por cualquier host en
|
||||
@@ -498,6 +525,11 @@ el tipo ARP para Token-Ring es 6.
|
||||
.B --dhcp-hostsfile=<archivo>
|
||||
Leer información host DHCP desde el archivo especificado. El archivo contiene información de un host por línea. El formato de una línea es igual que texto hacia la derecha de '=' en --dhcp-host. La ventaja de almacenar información host DHCP en este archivo es que puede ser cambiada sin tener que reiniciar dnsmasq. El archivo será re-leído cuando dnsmasq recibe un SIGHUP.
|
||||
.TP
|
||||
.B --dhcp-optsfile=<archivo>
|
||||
Leer información sobre opciones DHCP desde el archivo especificado. La
|
||||
ventaja de usar esta opción es la misma que con --dhcp-hostsfile: el
|
||||
archivo dhcp-optsfile será re-leído cuando dnsmasq recibe un SIGHUP.
|
||||
.TP
|
||||
.B \-Z, --read-ethers
|
||||
Leer /etc/ethers en busca de información sobre hosts para el servidor
|
||||
DHCP. El formato de /etc/ethers es una dirección de hardware, seguida
|
||||
@@ -580,6 +612,14 @@ excepto que la opci
|
||||
la lista de pedido de parámetros. Esto se necesita aveces, por ejemplo cuando
|
||||
enviando opciones a PXELinux.
|
||||
.TP
|
||||
.B --dhcp-no-override
|
||||
Deshabilitar la reutilización de los campos DHCP de nombre de servidor y
|
||||
archivo como espacio para opciones extra. Si puede, dnsmasq mueve la información
|
||||
del servidor boot y del nombre de archivo (de dhcp-boot) de sus campos dedicados
|
||||
hacia opciones DHCP. Esto crea espacio extra en el paquete DHCP para opciones,
|
||||
pero puede raramente confundir clientes viejos o defectuosos. Esta opción forza
|
||||
comportamiento "simple y sencillo" para prevenir problemas en tales casos.
|
||||
.TP
|
||||
.B \-U, --dhcp-vendorclass=<network-id>,<vendor-class>
|
||||
Trazar desde un string vendor-class a un network id. La mayoría de los
|
||||
clientes DHCP proveen una "vendor class" la cual representa, en cierto
|
||||
@@ -619,6 +659,11 @@ network-id es fijado.
|
||||
.B --dhcp-subscrid=<network-id>,<subscriber-id>
|
||||
Trazar de opciones relay subscriber-id RFC3993 a opciones network-id.
|
||||
.TP
|
||||
.B --dhcp-match=<network-id>,<número de opción>
|
||||
Fijar la opción network-id si el cliente envía un opción DHCP del nombre
|
||||
brindado. Esto puede ser utilizado para identificar clientes particulares
|
||||
que envían información usando números privados de opciones.
|
||||
.TP
|
||||
.B \-J, --dhcp-ignore=<network-id>[,<network-id>]
|
||||
Cuando todos los network ids brindados coincidan con el juego de
|
||||
network ids derivados de las clases net, host, y vendor, ignorar
|
||||
@@ -633,6 +678,14 @@ y en tal caso nombres de host proveidos por clientes DHCP siempre son
|
||||
ignorados, y hosts DHCP son agregados al DNS usando solo la configuración
|
||||
dhcp-host en dnsmasq y el contenido de /etc/hosts y /etc/ethers.
|
||||
.TP
|
||||
.B --dhcp-broadcast=<network-id>[,<network-id>]
|
||||
Cuando todos los network-ids brindados coinciden con el juego de network-ids
|
||||
derivados de la red, host, clases de vendedor y usuarios, siempre usar
|
||||
broadcast para comunicarse con el host cuando está sin configurar. La
|
||||
mayoría de clientes DHCP que necesitan respuestas broadcast fijan una
|
||||
opción en sus pedidos para que esto pase automaticamente, algunos
|
||||
clientes BOOTP viejos no lo hacen.
|
||||
.TP
|
||||
.B \-M, --dhcp-boot=[net:<network-id>,]<filename>,[<servername>[,<server address>]]
|
||||
Fijar opciones BOOTP que han de ser devueltas por el servidor DHCP. Nombre
|
||||
y dirección de servidor son opcionales: si no son brindadas, el nombre es
|
||||
@@ -716,7 +769,9 @@ es almacenado en DNSMASQ_TIME_REMAINING.
|
||||
Si un arriendo solía tener un nombre de host, el cual es removido, un
|
||||
evento "old" es generado con el nuevo estado del arriendo, (por ejemplo, sin
|
||||
nombre), y el nombre anterior es brindado en la variable de ambiente
|
||||
DNSMASQ_OLD_HOSTNAME.
|
||||
DNSMASQ_OLD_HOSTNAME. DNSMASQ_INTERFACE almacena el nombre de la interface
|
||||
en la cual llegó el pedido; esto no es fijado para acciones "viejas"
|
||||
cuando dnsmasq re-inicia.
|
||||
Todos los descriptores de archivo están cerrados
|
||||
excepto stdin, stdout, y stderr los cuales están abiertos a /dev/null
|
||||
(excepto en modo debug).
|
||||
@@ -812,13 +867,25 @@ un descriptor de archivo por cada coneccion TFTP concurrente, y por archivo
|
||||
único (mas algunos otros). De tal manera que servirle el mismo archivo
|
||||
simultáneo a n clientes requerirá el uso de n + 10 descriptores de archivo,
|
||||
y servirles archivos diferentes simultáneamente requerirá (2*n) + 10
|
||||
descriptores.
|
||||
descriptores. Si
|
||||
.B --tftp-port-range
|
||||
es brindado, eso puede afectar el número de conexiones simultáneas.
|
||||
.TP
|
||||
.B --tftp-no-blocksize
|
||||
No permitir que el servidor negocie la opción "blocksize" con un cliente.
|
||||
Algunos clientes con errores piden esta opción pero se portán mal cuando se
|
||||
les brinda.
|
||||
.TP
|
||||
.B --tftp-port-range=<inicio>,<final>
|
||||
Un servidor TFTP escucha por inicios de conexión en un puerto bien conocido
|
||||
(69), pero tambien usa un puerto dinamicamente seleccionado para cada
|
||||
conexión. Normalmente estos son seleccionados por el sistema operativo,
|
||||
pero esta opción especifica un rango de puertos para ser usado por transferencias
|
||||
TFTP. Esto puede ser útil cuando TFTP tiene que pasar atraves de un firewall.
|
||||
El comienzo del rango no puede ser menor a 1025 a menos que dnsmasq esté corriendo
|
||||
como root. El número de conexiones simultáneas está limitado por el tamaño del
|
||||
rango de puertos.
|
||||
.TP
|
||||
.B \-C, --conf-file=<archivo>
|
||||
Especificar un archivo de configuración diferente. La opción conf-file
|
||||
también es permitida en archivos de configuración, para incluir múltiples
|
||||
@@ -845,8 +912,8 @@ y son ignoradas. Para opciones que solo pueden ser especificadas una
|
||||
sola vez, el archivo de configuración invalida la línea de comandos.
|
||||
Las comillas son permitidas en el archivo de configuración: entre comillas
|
||||
tipo " los significados especiales de ,:. y # son eliminados y los
|
||||
siguientes escapes son permitidos: \\\\ \\" \\t \\a \\b \\r y \\n. El
|
||||
último corresponde a tab, bell, backspace, return y newline.
|
||||
siguientes escapes son permitidos: \\\\ \\" \\t \\e \\b \\r y \\n.
|
||||
Corresponden a tab, escape, backspace, return y newline.
|
||||
.SH NOTAS
|
||||
Al recibir un SIGHUP
|
||||
.B dnsmasq
|
||||
@@ -854,7 +921,8 @@ libera su cache y entonces recarga
|
||||
.I /etc/hosts
|
||||
y
|
||||
.I /etc/ethers
|
||||
al igual que cualquier archivo brindado con --dhcp-hostsfile.
|
||||
al igual que cualquier archivo brindado con --dhcp-hostsfile, --dhcp-optsfile,
|
||||
o --addn-hosts.
|
||||
El archivo guión de cambio de arriendos es llamado para todos los arriendos
|
||||
DHCP existentes. Si
|
||||
.B
|
||||
@@ -866,10 +934,12 @@ NO re-lee el archivo de configuraci
|
||||
.PP
|
||||
Al recibir un SIGUSR1,
|
||||
.B dnsmasq
|
||||
escribe estadísticas de caché a la bitácora del sistema. Escribe el tamaño
|
||||
escribe estadísticas a la bitácora del sistema. Escribe el tamaño
|
||||
del caché, el numero de nombres que han tenido que ser removidos del
|
||||
caché antes de que vencieran para hacer espacio para nombres nuevos, y el
|
||||
número total de nombres que han sido insertados en el caché. En modo
|
||||
número total de nombres que han sido insertados en el caché. Para cada
|
||||
servidor upstream brinda el número de búsquedas enviadas, y el
|
||||
número que resultaron en error. En modo
|
||||
.B --no-daemon
|
||||
o cuando bitacoréo completo está habilitado (-q), una descarga completa de
|
||||
el contenido del caché es hecha.
|
||||
|
||||
1297
man/fr/dnsmasq.8
Normal file
1297
man/fr/dnsmasq.8
Normal file
File diff suppressed because it is too large
Load Diff
1459
po/pt_BR.po
1459
po/pt_BR.po
File diff suppressed because it is too large
Load Diff
219
src/bpf.c
219
src/bpf.c
@@ -1,20 +1,22 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2006 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991.
|
||||
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifndef HAVE_LINUX_NETWORK
|
||||
|
||||
#include <net/bpf.h>
|
||||
#if defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
|
||||
|
||||
static struct iovec ifconf = {
|
||||
.iov_base = NULL,
|
||||
@@ -26,6 +28,107 @@ static struct iovec ifreq = {
|
||||
.iov_len = 0
|
||||
};
|
||||
|
||||
int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
|
||||
{
|
||||
char *ptr;
|
||||
struct ifreq *ifr;
|
||||
struct ifconf ifc;
|
||||
int fd, errsav, ret = 0;
|
||||
int lastlen = 0;
|
||||
size_t len = 0;
|
||||
|
||||
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
return 0;
|
||||
|
||||
while(1)
|
||||
{
|
||||
len += 10*sizeof(struct ifreq);
|
||||
|
||||
if (!expand_buf(&ifconf, len))
|
||||
goto err;
|
||||
|
||||
ifc.ifc_len = len;
|
||||
ifc.ifc_buf = ifconf.iov_base;
|
||||
|
||||
if (ioctl(fd, SIOCGIFCONF, &ifc) == -1)
|
||||
{
|
||||
if (errno != EINVAL || lastlen != 0)
|
||||
goto err;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ifc.ifc_len == lastlen)
|
||||
break; /* got a big enough buffer now */
|
||||
lastlen = ifc.ifc_len;
|
||||
}
|
||||
}
|
||||
|
||||
for (ptr = ifc.ifc_buf; ptr < ifc.ifc_buf + ifc.ifc_len; ptr += len )
|
||||
{
|
||||
/* subsequent entries may not be aligned, so copy into
|
||||
an aligned buffer to avoid nasty complaints about
|
||||
unaligned accesses. */
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
len = ((struct ifreq *)ptr)->ifr_addr.sa_len + offsetof(struct ifreq, ifr_ifru);
|
||||
#else
|
||||
len = sizeof(struct ifreq);
|
||||
#endif
|
||||
if (!expand_buf(&ifreq, len))
|
||||
goto err;
|
||||
|
||||
ifr = (struct ifreq *)ifreq.iov_base;
|
||||
memcpy(ifr, ptr, len);
|
||||
|
||||
if (ifr->ifr_addr.sa_family == AF_INET && ipv4_callback)
|
||||
{
|
||||
struct in_addr addr, netmask, broadcast;
|
||||
broadcast.s_addr = 0;
|
||||
addr = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (ioctl(fd, SIOCGIFNETMASK, ifr) == -1)
|
||||
continue;
|
||||
netmask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (ioctl(fd, SIOCGIFBRDADDR, ifr) != -1)
|
||||
broadcast = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (!((*ipv4_callback)(addr,
|
||||
(int)if_nametoindex(ifr->ifr_name),
|
||||
netmask, broadcast,
|
||||
parm)))
|
||||
goto err;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (ifr->ifr_addr.sa_family == AF_INET6 && ipv6_callback)
|
||||
{
|
||||
struct in6_addr *addr = &((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_addr;
|
||||
/* voodoo to clear interface field in address */
|
||||
if (!(daemon->options & OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
|
||||
{
|
||||
addr->s6_addr[2] = 0;
|
||||
addr->s6_addr[3] = 0;
|
||||
}
|
||||
if (!((*ipv6_callback)(addr,
|
||||
(int)((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_scope_id,
|
||||
(int)if_nametoindex(ifr->ifr_name),
|
||||
parm)))
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
errsav = errno;
|
||||
close(fd);
|
||||
errno = errsav;
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(HAVE_BSD_NETWORK)
|
||||
#include <net/bpf.h>
|
||||
|
||||
void init_bpf(void)
|
||||
{
|
||||
int i = 0;
|
||||
@@ -109,15 +212,17 @@ void send_via_bpf(struct dhcp_packet *mess, size_t len,
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
ip.ip_sum = (sum == 0xffff) ? sum : ~sum;
|
||||
|
||||
udp.uh_sport = htons(DHCP_SERVER_PORT);
|
||||
udp.uh_dport = htons(DHCP_CLIENT_PORT);
|
||||
udp.uh_sport = htons(daemon->dhcp_server_port);
|
||||
udp.uh_dport = htons(daemon->dhcp_client_port);
|
||||
if (len & 1)
|
||||
((char *)mess)[len] = 0; /* for checksum, in case length is odd. */
|
||||
udp.uh_sum = 0;
|
||||
udp.uh_ulen = sum = htons(sizeof(struct udphdr) + len);
|
||||
sum += htons(IPPROTO_UDP);
|
||||
for (i = 0; i < 4; i++)
|
||||
sum += ((u16 *)&ip.ip_src)[i];
|
||||
sum += ip.ip_src.s_addr & 0xffff;
|
||||
sum += (ip.ip_src.s_addr >> 16) & 0xffff;
|
||||
sum += ip.ip_dst.s_addr & 0xffff;
|
||||
sum += (ip.ip_dst.s_addr >> 16) & 0xffff;
|
||||
for (i = 0; i < sizeof(struct udphdr)/2; i++)
|
||||
sum += ((u16 *)&udp)[i];
|
||||
for (i = 0; i < (len + 1) / 2; i++)
|
||||
@@ -140,100 +245,6 @@ void send_via_bpf(struct dhcp_packet *mess, size_t len,
|
||||
while (writev(daemon->dhcp_raw_fd, iov, 4) == -1 && retry_send());
|
||||
}
|
||||
|
||||
int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
|
||||
{
|
||||
char *ptr;
|
||||
struct ifreq *ifr;
|
||||
struct ifconf ifc;
|
||||
int fd, errsav, ret = 0;
|
||||
int lastlen = 0;
|
||||
size_t len = 0;
|
||||
|
||||
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
return 0;
|
||||
|
||||
while(1)
|
||||
{
|
||||
len += 10*sizeof(struct ifreq);
|
||||
|
||||
if (!expand_buf(&ifconf, len))
|
||||
goto err;
|
||||
|
||||
ifc.ifc_len = len;
|
||||
ifc.ifc_buf = ifconf.iov_base;
|
||||
|
||||
if (ioctl(fd, SIOCGIFCONF, &ifc) == -1)
|
||||
{
|
||||
if (errno != EINVAL || lastlen != 0)
|
||||
goto err;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ifc.ifc_len == lastlen)
|
||||
break; /* got a big enough buffer now */
|
||||
lastlen = ifc.ifc_len;
|
||||
}
|
||||
}
|
||||
|
||||
for (ptr = ifc.ifc_buf; ptr < ifc.ifc_buf + ifc.ifc_len; ptr += len )
|
||||
{
|
||||
/* subsequent entries may not be aligned, so copy into
|
||||
an aligned buffer to avoid nasty complaints about
|
||||
unaligned accesses. */
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
len = ((struct ifreq *)ptr)->ifr_addr.sa_len + IF_NAMESIZE;
|
||||
#else
|
||||
len = sizeof(struct ifreq);
|
||||
#endif
|
||||
if (!expand_buf(&ifreq, len))
|
||||
goto err;
|
||||
|
||||
ifr = ifreq.iov_base;
|
||||
memcpy(ifr, ptr, len);
|
||||
|
||||
if (ifr->ifr_addr.sa_family == AF_INET && ipv4_callback)
|
||||
{
|
||||
struct in_addr addr, netmask, broadcast;
|
||||
broadcast.s_addr = 0;
|
||||
addr = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (ioctl(fd, SIOCGIFNETMASK, ifr) == -1)
|
||||
continue;
|
||||
netmask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (ioctl(fd, SIOCGIFBRDADDR, ifr) != -1)
|
||||
broadcast = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (!((*ipv4_callback)(addr,
|
||||
(int)if_nametoindex(ifr->ifr_name),
|
||||
netmask, broadcast,
|
||||
parm)))
|
||||
goto err;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (ifr->ifr_addr.sa_family == AF_INET6 && ipv6_callback)
|
||||
{
|
||||
struct in6_addr *addr = &((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_addr;
|
||||
/* voodoo to clear interface field in address */
|
||||
if (!(daemon->options & OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
|
||||
{
|
||||
addr->s6_addr[2] = 0;
|
||||
addr->s6_addr[3] = 0;
|
||||
}
|
||||
if (!((*ipv6_callback)(addr,
|
||||
(int)((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_scope_id,
|
||||
(int)if_nametoindex(ifr->ifr_name),
|
||||
parm)))
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
errsav = errno;
|
||||
close(fd);
|
||||
errno = errsav;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
176
src/cache.c
176
src/cache.c
@@ -2,12 +2,16 @@
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991.
|
||||
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
@@ -41,6 +45,7 @@ static const struct {
|
||||
{ 25, "KEY" },
|
||||
{ 28, "AAAA" },
|
||||
{ 33, "SRV" },
|
||||
{ 35, "NAPTR" },
|
||||
{ 36, "KX" },
|
||||
{ 37, "CERT" },
|
||||
{ 38, "A6" },
|
||||
@@ -59,7 +64,6 @@ static const struct {
|
||||
static void cache_free(struct crec *crecp);
|
||||
static void cache_unlink(struct crec *crecp);
|
||||
static void cache_link(struct crec *crecp);
|
||||
static char *record_source(struct hostsfile *add_hosts, int index);
|
||||
static void rehash(int size);
|
||||
static void cache_hash(struct crec *crecp);
|
||||
|
||||
@@ -355,8 +359,9 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
struct crec *new;
|
||||
union bigname *big_name = NULL;
|
||||
int freed_all = flags & F_REVERSE;
|
||||
int free_avail = 0;
|
||||
|
||||
log_query(flags | F_UPSTREAM, name, addr, 0, NULL, 0);
|
||||
log_query(flags | F_UPSTREAM, name, addr, NULL);
|
||||
|
||||
/* CONFIG bit no needed except for logging */
|
||||
flags &= ~F_CONFIG;
|
||||
@@ -388,8 +393,19 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
|
||||
if (new->flags & (F_FORWARD | F_REVERSE))
|
||||
{
|
||||
/* If free_avail set, we believe that an entry has been freed.
|
||||
Bugs have been known to make this not true, resulting in
|
||||
a tight loop here. If that happens, abandon the
|
||||
insert. Once in this state, all inserts will probably fail. */
|
||||
if (free_avail)
|
||||
{
|
||||
insert_error = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (freed_all)
|
||||
{
|
||||
free_avail = 1; /* Must be free space now. */
|
||||
cache_scan_free(cache_get_name(new), &new->addr.addr, now, new->flags);
|
||||
cache_live_freed++;
|
||||
}
|
||||
@@ -484,7 +500,8 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
|
||||
/* first search, look for relevant entries and push to top of list
|
||||
also free anything which has expired */
|
||||
struct crec *next, **up, **insert = NULL, **chainp = &ans;
|
||||
|
||||
int ins_flags = 0;
|
||||
|
||||
for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
|
||||
{
|
||||
next = crecp->hash_next;
|
||||
@@ -506,20 +523,27 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
|
||||
cache_link(crecp);
|
||||
}
|
||||
|
||||
/* move all but the first entry up the hash chain
|
||||
this implements round-robin */
|
||||
if (!insert)
|
||||
{
|
||||
insert = up;
|
||||
up = &crecp->hash_next;
|
||||
}
|
||||
else
|
||||
/* Move all but the first entry up the hash chain
|
||||
this implements round-robin.
|
||||
Make sure that re-ordering doesn't break the hash-chain
|
||||
order invariants.
|
||||
*/
|
||||
if (insert && (crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags)
|
||||
{
|
||||
*up = crecp->hash_next;
|
||||
crecp->hash_next = *insert;
|
||||
*insert = crecp;
|
||||
insert = &crecp->hash_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!insert)
|
||||
{
|
||||
insert = up;
|
||||
ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
|
||||
}
|
||||
up = &crecp->hash_next;
|
||||
}
|
||||
}
|
||||
else
|
||||
/* case : not expired, incorrect entry. */
|
||||
@@ -827,14 +851,16 @@ void cache_unhash_dhcp(void)
|
||||
void cache_add_dhcp_entry(char *host_name,
|
||||
struct in_addr *host_address, time_t ttd)
|
||||
{
|
||||
struct crec *crec;
|
||||
struct crec *crec = NULL;
|
||||
unsigned short flags = F_DHCP | F_FORWARD | F_IPV4 | F_REVERSE;
|
||||
int in_hosts = 0;
|
||||
|
||||
if (!host_name)
|
||||
return;
|
||||
|
||||
if ((crec = cache_find_by_name(NULL, host_name, 0, F_IPV4 | F_CNAME)))
|
||||
while ((crec = cache_find_by_name(crec, host_name, 0, F_IPV4 | F_CNAME)))
|
||||
{
|
||||
/* check all addresses associated with name */
|
||||
if (crec->flags & F_HOSTS)
|
||||
{
|
||||
if (crec->addr.addr.addr.addr4.s_addr != host_address->s_addr)
|
||||
@@ -845,23 +871,33 @@ void cache_add_dhcp_entry(char *host_name,
|
||||
"the name exists in %s with address %s"),
|
||||
host_name, inet_ntoa(*host_address),
|
||||
record_source(daemon->addn_hosts, crec->uid), daemon->namebuff);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
else
|
||||
/* if in hosts, don't need DHCP record */
|
||||
in_hosts = 1;
|
||||
}
|
||||
else if (!(crec->flags & F_DHCP))
|
||||
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->flags & F_NEG)
|
||||
cache_scan_free(NULL, (struct all_addr *)host_address, 0, F_IPV4 | F_REVERSE);
|
||||
else
|
||||
/* avoid multiple reverse mappings */
|
||||
flags &= ~F_REVERSE;
|
||||
{
|
||||
cache_scan_free(host_name, NULL, 0, crec->flags & (F_IPV4 | F_CNAME | F_FORWARD));
|
||||
/* scan_free deletes all addresses associated with name */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (in_hosts)
|
||||
return;
|
||||
|
||||
if ((crec = dhcp_spare))
|
||||
if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, F_IPV4)))
|
||||
{
|
||||
if (crec->flags & F_NEG)
|
||||
cache_scan_free(NULL, (struct all_addr *)host_address, 0, F_IPV4 | F_REVERSE);
|
||||
else
|
||||
/* avoid multiple reverse mappings */
|
||||
flags &= ~F_REVERSE;
|
||||
}
|
||||
|
||||
if ((crec = dhcp_spare))
|
||||
dhcp_spare = dhcp_spare->next;
|
||||
else /* need new one */
|
||||
crec = whine_malloc(sizeof(struct crec));
|
||||
@@ -881,11 +917,38 @@ void cache_add_dhcp_entry(char *host_name,
|
||||
|
||||
void dump_cache(time_t now)
|
||||
{
|
||||
my_syslog(LOG_INFO, _("time %lu, cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
|
||||
(unsigned long)now, daemon->cachesize, cache_live_freed, cache_inserted);
|
||||
struct server *serv, *serv1;
|
||||
|
||||
my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);
|
||||
my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
|
||||
daemon->cachesize, cache_live_freed, cache_inserted);
|
||||
my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
|
||||
daemon->queries_forwarded, daemon->local_answer);
|
||||
|
||||
if (!addrbuff && !(addrbuff = whine_malloc(ADDRSTRLEN)))
|
||||
return;
|
||||
|
||||
/* sum counts from different records for same server */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
serv->flags &= ~SERV_COUNTED;
|
||||
|
||||
if ((daemon->options & (OPT_DEBUG | OPT_LOG)) &&
|
||||
(addrbuff || (addrbuff = whine_malloc(ADDRSTRLEN))))
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (!(serv->flags & (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED)))
|
||||
{
|
||||
int port;
|
||||
unsigned int queries = 0, failed_queries = 0;
|
||||
for (serv1 = serv; serv1; serv1 = serv1->next)
|
||||
if (!(serv1->flags & (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED)) && sockaddr_isequal(&serv->addr, &serv1->addr))
|
||||
{
|
||||
serv1->flags |= SERV_COUNTED;
|
||||
queries += serv1->queries;
|
||||
failed_queries += serv1->failed_queries;
|
||||
}
|
||||
port = prettyprint_addr(&serv->addr, addrbuff);
|
||||
my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried or failed %u"), addrbuff, port, queries, failed_queries);
|
||||
}
|
||||
|
||||
if ((daemon->options & (OPT_DEBUG | OPT_LOG)))
|
||||
{
|
||||
struct crec *cache ;
|
||||
int i;
|
||||
@@ -940,7 +1003,7 @@ void dump_cache(time_t now)
|
||||
}
|
||||
}
|
||||
|
||||
static char *record_source(struct hostsfile *addn_hosts, int index)
|
||||
char *record_source(struct hostsfile *addn_hosts, int index)
|
||||
{
|
||||
char *source = HOSTSFILE;
|
||||
while (addn_hosts)
|
||||
@@ -956,12 +1019,20 @@ static char *record_source(struct hostsfile *addn_hosts, int index)
|
||||
return source;
|
||||
}
|
||||
|
||||
void log_query(unsigned short flags, char *name, struct all_addr *addr,
|
||||
unsigned short type, struct hostsfile *addn_hosts, int index)
|
||||
void querystr(char *str, unsigned short type)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
sprintf(str, "query[type=%d]", type);
|
||||
for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
|
||||
if (typestr[i].type == type)
|
||||
sprintf(str,"query[%s]", typestr[i].name);
|
||||
}
|
||||
|
||||
void log_query(unsigned short flags, char *name, struct all_addr *addr, char *arg)
|
||||
{
|
||||
char *source, *dest = addrbuff;
|
||||
char *verb = "is";
|
||||
char types[20];
|
||||
|
||||
if (!(daemon->options & OPT_LOG))
|
||||
return;
|
||||
@@ -988,28 +1059,26 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr,
|
||||
{
|
||||
if (flags & F_IPV4)
|
||||
dest = "NXDOMAIN-IPv4";
|
||||
else
|
||||
dest = "NXDOMAIN-IPv6";
|
||||
else if (flags & F_IPV6)
|
||||
dest = "NXDOMAIN-IPv6";
|
||||
else
|
||||
dest = "NXDOMAIN";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flags & F_IPV4)
|
||||
dest = "NODATA-IPv4";
|
||||
else
|
||||
else if (flags & F_IPV6)
|
||||
dest = "NODATA-IPv6";
|
||||
else
|
||||
dest = "NODATA";
|
||||
}
|
||||
}
|
||||
else if (flags & F_CNAME)
|
||||
{
|
||||
/* nasty abuse of IPV4 and IPV6 flags */
|
||||
if (flags & F_IPV4)
|
||||
dest = "<MX>";
|
||||
else if (flags & F_IPV6)
|
||||
dest = "<SRV>";
|
||||
else if (flags & F_NXDOMAIN)
|
||||
dest = "<TXT>";
|
||||
else if (flags & F_BIGNAME)
|
||||
dest = "<PTR>";
|
||||
/* nasty abuse of NXDOMAIN and CNAME flags */
|
||||
if (flags & F_NXDOMAIN)
|
||||
dest = arg;
|
||||
else
|
||||
dest = "<CNAME>";
|
||||
}
|
||||
@@ -1017,7 +1086,7 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr,
|
||||
if (flags & F_DHCP)
|
||||
source = "DHCP";
|
||||
else if (flags & F_HOSTS)
|
||||
source = record_source(addn_hosts, index);
|
||||
source = arg;
|
||||
else if (flags & F_CONFIG)
|
||||
source = "config";
|
||||
else if (flags & F_UPSTREAM)
|
||||
@@ -1029,16 +1098,7 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr,
|
||||
}
|
||||
else if (flags & F_QUERY)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (type != 0)
|
||||
{
|
||||
sprintf(types, "query[type=%d]", type);
|
||||
for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
|
||||
if (typestr[i].type == type)
|
||||
sprintf(types,"query[%s]", typestr[i].name);
|
||||
}
|
||||
source = types;
|
||||
source = arg;
|
||||
verb = "from";
|
||||
}
|
||||
else
|
||||
|
||||
132
src/config.h
132
src/config.h
@@ -2,21 +2,26 @@
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991.
|
||||
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define VERSION "2.40"
|
||||
#define VERSION "2.43"
|
||||
|
||||
#define FTABSIZ 150 /* max number of outstanding requests (default) */
|
||||
#define MAX_PROCS 20 /* max no children for TCP requests */
|
||||
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
|
||||
#define EDNS_PKTSZ 1280 /* default max EDNS.0 UDP packet from RFC2671 */
|
||||
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
|
||||
#define RANDOM_SOCKS 64 /* max simultaneous random ports */
|
||||
#define LEASE_RETRY 60 /* on error, retry writing leasefile after LEASE_RETRY seconds */
|
||||
#define CACHESIZ 150 /* default cache size */
|
||||
#define MAXLEASES 150 /* maximum number of DHCP leases */
|
||||
@@ -35,6 +40,8 @@
|
||||
#define RUNFILE "/var/run/dnsmasq.pid"
|
||||
#if defined(__FreeBSD__) || defined (__OpenBSD__) || defined(__DragonFly__)
|
||||
# define LEASEFILE "/var/db/dnsmasq.leases"
|
||||
#elif defined(__sun__) || defined (__sun)
|
||||
# define LEASEFILE "/var/cache/dnsmasq.leases"
|
||||
#else
|
||||
# define LEASEFILE "/var/lib/misc/dnsmasq.leases"
|
||||
#endif
|
||||
@@ -48,9 +55,12 @@
|
||||
#define CHGRP "dip"
|
||||
#define DHCP_SERVER_PORT 67
|
||||
#define DHCP_CLIENT_PORT 68
|
||||
#define DHCP_SERVER_ALTPORT 1067
|
||||
#define DHCP_CLIENT_ALTPORT 1068
|
||||
#define TFTP_PORT 69
|
||||
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
|
||||
#define LOG_MAX 5 /* log-queue length */
|
||||
#define RANDFILE "/dev/urandom"
|
||||
|
||||
/* DBUS interface specifics */
|
||||
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq"
|
||||
@@ -79,22 +89,17 @@
|
||||
#endif
|
||||
|
||||
|
||||
/* Get linux C library versions. */
|
||||
#if defined(__linux__) && !defined(__UCLIBC__) && !defined(__uClinux__)
|
||||
/*# include <libio.h> */
|
||||
# include <features.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* Follows system specific switches. If you run on a
|
||||
new system, you may want to edit these.
|
||||
May replace this with Autoconf one day.
|
||||
|
||||
HAVE_LINUX_NETWORK
|
||||
define this to do networking the Linux way. When it's defined, the code will
|
||||
use IP_PKTINFO, Linux capabilities and the RTnetlink system. If it's not defined,
|
||||
a few facilities will be lost, namely support for multiple addresses on an interface,
|
||||
DNS query retransmission, and (on some systems) wildcard interface binding.
|
||||
HAVE_BSD_NETWORK
|
||||
HAVE_SOLARIS_NETWORK
|
||||
define exactly one of these to alter interaction with kernel networking.
|
||||
|
||||
HAVE_SOLARIS_PRIVS
|
||||
define for Solaris > 10 which can split privileges.
|
||||
|
||||
HAVE_BROKEN_RTC
|
||||
define this on embedded systems which don't have an RTC
|
||||
@@ -124,19 +129,6 @@ HAVE_ARC4RANDOM
|
||||
define this if you have arc4random() to get better security from DNS spoofs
|
||||
by using really random ids (OpenBSD)
|
||||
|
||||
HAVE_RANDOM
|
||||
define this if you have the 4.2BSD random() function (and its
|
||||
associated srandom() function), which is at least as good as (if not
|
||||
better than) the rand() function.
|
||||
|
||||
HAVE_DEV_RANDOM
|
||||
define this if you have the /dev/random device, which gives truly
|
||||
random numbers but may run out of random numbers.
|
||||
|
||||
HAVE_DEV_URANDOM
|
||||
define this if you have the /dev/urandom device, which gives
|
||||
semi-random numbers when it runs out of truly random numbers.
|
||||
|
||||
HAVE_SOCKADDR_SA_LEN
|
||||
define this if struct sockaddr has sa_len field (*BSD)
|
||||
|
||||
@@ -145,27 +137,27 @@ HAVE_DBUS
|
||||
define some methods to allow (re)configuration of the upstream DNS
|
||||
servers via DBus.
|
||||
|
||||
HAVE_BSD_BRIDGE
|
||||
Define this to enable the --bridge-interface option, useful on some
|
||||
BSD systems.
|
||||
|
||||
HAVE_LARGFILE
|
||||
Define this if the C library supports large (>2GB) files probably true everywhere
|
||||
except some builds of uclibc
|
||||
|
||||
NOTES:
|
||||
For Linux you should define
|
||||
HAVE_LINUX_NETWORK
|
||||
HAVE_GETOPT_LONG
|
||||
HAVE_RANDOM
|
||||
HAVE_DEV_RANDOM
|
||||
HAVE_DEV_URANDOM
|
||||
you should NOT define
|
||||
HAVE_ARC4RANDOM
|
||||
HAVE_SOCKADDR_SA_LEN
|
||||
|
||||
For *BSD systems you should define
|
||||
HAVE_BSD_NETWORK
|
||||
HAVE_SOCKADDR_SA_LEN
|
||||
HAVE_RANDOM
|
||||
you should NOT define
|
||||
HAVE_LINUX_NETWORK
|
||||
and you MAY define
|
||||
HAVE_ARC4RANDOM - OpenBSD and FreeBSD and NetBSD version 2.0 or later
|
||||
HAVE_DEV_URANDOM - OpenBSD and FreeBSD and NetBSD
|
||||
HAVE_DEV_RANDOM - FreeBSD and NetBSD
|
||||
(OpenBSD with hardware random number generator)
|
||||
HAVE_GETOPT_LONG - NetBSD, later FreeBSD
|
||||
(FreeBSD and OpenBSD only if you link GNU getopt)
|
||||
|
||||
@@ -181,7 +173,7 @@ NOTES:
|
||||
# error HAVE_ISC_READER is not compatible with HAVE_BROKEN_RTC
|
||||
#endif
|
||||
|
||||
/* Allow TFTP to be disabled with COPT=-DNO_TFTP */
|
||||
/* Allow TFTP to be disabled with COPTS=-DNO_TFTP */
|
||||
#ifdef NO_TFTP
|
||||
#undef HAVE_TFTP
|
||||
#endif
|
||||
@@ -193,9 +185,6 @@ NOTES:
|
||||
#define HAVE_LINUX_NETWORK
|
||||
#define HAVE_GETOPT_LONG
|
||||
#undef HAVE_ARC4RANDOM
|
||||
#define HAVE_RANDOM
|
||||
#define HAVE_DEV_URANDOM
|
||||
#define HAVE_DEV_RANDOM
|
||||
#undef HAVE_SOCKADDR_SA_LEN
|
||||
/* Never use fork() on uClinux. Note that this is subtly different from the
|
||||
--keep-in-foreground option, since it also suppresses forking new
|
||||
@@ -208,13 +197,8 @@ NOTES:
|
||||
#if defined(__UCLIBC_HAS_GNU_GETOPT__) || \
|
||||
((__UCLIBC_MAJOR__==0) && (__UCLIBC_MINOR__==9) && (__UCLIBC_SUBLEVEL__<21))
|
||||
# define HAVE_GETOPT_LONG
|
||||
#else
|
||||
# undef HAVE_GETOPT_LONG
|
||||
#endif
|
||||
#undef HAVE_ARC4RANDOM
|
||||
#define HAVE_RANDOM
|
||||
#define HAVE_DEV_URANDOM
|
||||
#define HAVE_DEV_RANDOM
|
||||
#undef HAVE_SOCKADDR_SA_LEN
|
||||
#if !defined(__ARCH_HAS_MMU__) && !defined(__UCLIBC_HAS_MMU__)
|
||||
# define NO_FORK
|
||||
@@ -230,9 +214,6 @@ NOTES:
|
||||
#define HAVE_LINUX_NETWORK
|
||||
#define HAVE_GETOPT_LONG
|
||||
#undef HAVE_ARC4RANDOM
|
||||
#define HAVE_RANDOM
|
||||
#define HAVE_DEV_URANDOM
|
||||
#define HAVE_DEV_RANDOM
|
||||
#undef HAVE_SOCKADDR_SA_LEN
|
||||
/* glibc < 2.2 has broken Sockaddr_in6 so we have to use our own. */
|
||||
/* glibc < 2.2 doesn't define in_addr_t */
|
||||
@@ -242,25 +223,25 @@ typedef unsigned long in_addr_t;
|
||||
# define HAVE_BROKEN_SOCKADDR_IN6
|
||||
#endif
|
||||
|
||||
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
|
||||
#undef HAVE_LINUX_NETWORK
|
||||
#elif defined(__FreeBSD__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__DragonFly__) || \
|
||||
defined (__FreeBSD_kernel__)
|
||||
#define HAVE_BSD_NETWORK
|
||||
/* Later verions of FreeBSD have getopt_long() */
|
||||
#if defined(optional_argument) && defined(required_argument)
|
||||
# define HAVE_GETOPT_LONG
|
||||
#else
|
||||
# undef HAVE_GETOPT_LONG
|
||||
#endif
|
||||
#define HAVE_ARC4RANDOM
|
||||
#define HAVE_RANDOM
|
||||
#define HAVE_DEV_URANDOM
|
||||
#if !defined (__FreeBSD_kernel__)
|
||||
# define HAVE_ARC4RANDOM
|
||||
#endif
|
||||
#define HAVE_SOCKADDR_SA_LEN
|
||||
#define HAVE_BSD_BRIDGE
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
#undef HAVE_LINUX_NETWORK
|
||||
#define HAVE_BSD_NETWORK
|
||||
#undef HAVE_GETOPT_LONG
|
||||
#define HAVE_ARC4RANDOM
|
||||
#define HAVE_RANDOM
|
||||
#define HAVE_DEV_URANDOM
|
||||
#define HAVE_SOCKADDR_SA_LEN
|
||||
/* Define before sys/socket.h is included so we get socklen_t */
|
||||
#define _BSD_SOCKLEN_T_
|
||||
@@ -268,15 +249,40 @@ typedef unsigned long in_addr_t;
|
||||
#define IN6ADDRSZ 16
|
||||
|
||||
#elif defined(__NetBSD__)
|
||||
#undef HAVE_LINUX_NETWORK
|
||||
#define HAVE_BSD_NETWORK
|
||||
#define HAVE_GETOPT_LONG
|
||||
#undef HAVE_ARC4RANDOM
|
||||
#define HAVE_RANDOM
|
||||
#define HAVE_DEV_URANDOM
|
||||
#define HAVE_DEV_RANDOM
|
||||
#define HAVE_SOCKADDR_SA_LEN
|
||||
|
||||
#define HAVE_BSD_BRIDGE
|
||||
|
||||
#elif defined(__sun) || defined(__sun__)
|
||||
#define HAVE_SOLARIS_NETWORK
|
||||
/* only Solaris 10 does split privs. */
|
||||
#if (SUNOS_VER >= 10)
|
||||
# define HAVE_SOLARIS_PRIVS
|
||||
# define HAVE_GETOPT_LONG
|
||||
#endif
|
||||
/* some CMSG stuff missing on early solaris */
|
||||
#ifndef OSSH_ALIGNBYTES
|
||||
# define OSSH_ALIGNBYTES (sizeof(int) - 1)
|
||||
#endif
|
||||
#ifndef __CMSG_ALIGN
|
||||
# define __CMSG_ALIGN(p) (((u_int)(p) + OSSH_ALIGNBYTES) &~ OSSH_ALIGNBYTES)
|
||||
#endif
|
||||
#ifndef CMSG_LEN
|
||||
# define CMSG_LEN(len) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
|
||||
#endif
|
||||
#ifndef CMSG_SPACE
|
||||
# define CMSG_SPACE(len) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + __CMSG_ALIGN(len))
|
||||
#endif
|
||||
#undef HAVE_ARC4RANDOM
|
||||
#undef HAVE_SOCKADDR_SA_LEN
|
||||
|
||||
#define _XPG4_2
|
||||
#define __EXTENSIONS__
|
||||
#define ETHER_ADDR_LEN 6
|
||||
#endif
|
||||
|
||||
/* Decide if we're going to support IPv6 */
|
||||
/* IPv6 can be forced off with "make COPTS=-DNO_IPV6" */
|
||||
/* We assume that systems which don't have IPv6
|
||||
|
||||
26
src/dbus.c
26
src/dbus.c
@@ -1,13 +1,17 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2005 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991.
|
||||
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
@@ -112,9 +116,9 @@ static void dbus_read_servers(DBusMessage *message)
|
||||
#else
|
||||
if (i == sizeof(struct in6_addr)-1)
|
||||
{
|
||||
memcpy(&addr.in6.sin6_addr, p, sizeof(addr.in6));
|
||||
memcpy(&addr.in6.sin6_addr, p, sizeof(struct in6_addr));
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(addr.in6);
|
||||
source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(struct sockaddr_in6);
|
||||
#endif
|
||||
source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
|
||||
addr.in6.sin6_port = htons(NAMESERVER_PORT);
|
||||
@@ -163,8 +167,11 @@ static void dbus_read_servers(DBusMessage *message)
|
||||
if (!serv && (serv = whine_malloc(sizeof (struct server))))
|
||||
{
|
||||
/* Not found, create a new one. */
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
|
||||
if (domain)
|
||||
serv->domain = whine_malloc(strlen(domain)+1);
|
||||
|
||||
if (domain && !serv->domain)
|
||||
{
|
||||
free(serv);
|
||||
@@ -175,7 +182,6 @@ static void dbus_read_servers(DBusMessage *message)
|
||||
serv->next = daemon->servers;
|
||||
daemon->servers = serv;
|
||||
serv->flags = SERV_FROM_DBUS;
|
||||
serv->sfd = NULL;
|
||||
if (domain)
|
||||
{
|
||||
strcpy(serv->domain, domain);
|
||||
@@ -292,7 +298,11 @@ void set_dbus_listeners(int *maxfdp,
|
||||
if (dbus_watch_get_enabled(w->watch))
|
||||
{
|
||||
unsigned int flags = dbus_watch_get_flags(w->watch);
|
||||
#if (DBUS_MINOR > 0)
|
||||
int fd = dbus_watch_get_unix_fd(w->watch);
|
||||
#else
|
||||
int fd = dbus_watch_get_fd(w->watch);
|
||||
#endif
|
||||
|
||||
bump_maxfd(fd, maxfdp);
|
||||
|
||||
@@ -315,7 +325,11 @@ void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset)
|
||||
if (dbus_watch_get_enabled(w->watch))
|
||||
{
|
||||
unsigned int flags = 0;
|
||||
#if (DBUS_MINOR > 0)
|
||||
int fd = dbus_watch_get_unix_fd(w->watch);
|
||||
#else
|
||||
int fd = dbus_watch_get_fd(w->watch);
|
||||
#endif
|
||||
|
||||
if (FD_ISSET(fd, rset))
|
||||
flags |= DBUS_WATCH_READABLE;
|
||||
|
||||
292
src/dhcp.c
292
src/dhcp.c
@@ -1,13 +1,17 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2006 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991.
|
||||
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
@@ -26,12 +30,17 @@ void dhcp_init(void)
|
||||
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
struct sockaddr_in saddr;
|
||||
int oneopt = 1;
|
||||
struct dhcp_config *configs, *cp;
|
||||
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
||||
int mtu = IP_PMTUDISC_DONT;
|
||||
#endif
|
||||
|
||||
if (fd == -1)
|
||||
die (_("cannot create DHCP socket : %s"), NULL, EC_BADNET);
|
||||
|
||||
if (!fix_fd(fd) ||
|
||||
if (!fix_fd(fd) ||
|
||||
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
||||
setsockopt(fd, SOL_IP, IP_MTU_DISCOVER, &mtu, sizeof(mtu)) == -1 ||
|
||||
#endif
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
setsockopt(fd, SOL_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
|
||||
#elif defined(IP_RECVIF)
|
||||
@@ -62,7 +71,7 @@ void dhcp_init(void)
|
||||
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
saddr.sin_family = AF_INET;
|
||||
saddr.sin_port = htons(DHCP_SERVER_PORT);
|
||||
saddr.sin_port = htons(daemon->dhcp_server_port);
|
||||
saddr.sin_addr.s_addr = INADDR_ANY;
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
saddr.sin_len = sizeof(struct sockaddr_in);
|
||||
@@ -73,7 +82,7 @@ void dhcp_init(void)
|
||||
|
||||
daemon->dhcpfd = fd;
|
||||
|
||||
#ifndef HAVE_LINUX_NETWORK
|
||||
#if defined(HAVE_BSD_NETWORK)
|
||||
/* When we're not using capabilities, we need to do this here before
|
||||
we drop root. Also, set buffer size small, to avoid wasting
|
||||
kernel buffers */
|
||||
@@ -88,21 +97,8 @@ void dhcp_init(void)
|
||||
init_bpf();
|
||||
#endif
|
||||
|
||||
/* If the same IP appears in more than one host config, then DISCOVER
|
||||
for one of the hosts will get the address, but REQUEST will be NAKed,
|
||||
since the address is reserved by the other one -> protocol loop.
|
||||
Also check that FQDNs match the domain we are using. */
|
||||
for (configs = daemon->dhcp_conf; configs; configs = configs->next)
|
||||
{
|
||||
char *domain;
|
||||
for (cp = configs->next; cp; cp = cp->next)
|
||||
if ((configs->flags & cp->flags & CONFIG_ADDR) && configs->addr.s_addr == cp->addr.s_addr)
|
||||
die(_("duplicate IP address %s in dhcp-config directive."), inet_ntoa(cp->addr), EC_BADCONF);
|
||||
|
||||
if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname)))
|
||||
die(_("illegal domain %s in dhcp-config directive."), domain, EC_BADCONF);
|
||||
}
|
||||
|
||||
check_dhcp_hosts(1);
|
||||
|
||||
daemon->dhcp_packet.iov_len = sizeof(struct dhcp_packet);
|
||||
daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len);
|
||||
}
|
||||
@@ -124,9 +120,11 @@ void dhcp_packet(time_t now)
|
||||
|
||||
union {
|
||||
struct cmsghdr align; /* this ensures alignment */
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
|
||||
#else
|
||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||
char control[CMSG_SPACE(sizeof(unsigned int))];
|
||||
#elif defined(IP_RECVIF)
|
||||
char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
|
||||
#endif
|
||||
} control_u;
|
||||
@@ -147,7 +145,7 @@ void dhcp_packet(time_t now)
|
||||
expand_buf(&daemon->dhcp_packet, daemon->dhcp_packet.iov_len + 100));
|
||||
|
||||
/* expand_buf may have moved buffer */
|
||||
mess = daemon->dhcp_packet.iov_base;
|
||||
mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
|
||||
msg.msg_controllen = sizeof(control_u);
|
||||
msg.msg_control = control_u.control;
|
||||
msg.msg_flags = 0;
|
||||
@@ -177,8 +175,12 @@ void dhcp_packet(time_t now)
|
||||
if (msg.msg_controllen >= sizeof(struct cmsghdr))
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
|
||||
iface_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
|
||||
|
||||
#ifdef HAVE_SOLARIS_NETWORK
|
||||
iface_index = *((unsigned int *)CMSG_DATA(cmptr));
|
||||
#else
|
||||
iface_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
|
||||
#endif
|
||||
|
||||
if (!iface_index || !if_indextoname(iface_index, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
@@ -198,7 +200,7 @@ void dhcp_packet(time_t now)
|
||||
iface_index = if_nametoindex(name->name);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
|
||||
{
|
||||
@@ -237,7 +239,7 @@ void dhcp_packet(time_t now)
|
||||
if (!iface_enumerate(&parm, complete_context, NULL))
|
||||
return;
|
||||
lease_prune(NULL, now); /* lose any expired leases */
|
||||
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, (size_t)sz,
|
||||
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
|
||||
now, unicast_dest, &is_inform);
|
||||
lease_update_file(now);
|
||||
lease_update_dns();
|
||||
@@ -253,7 +255,7 @@ void dhcp_packet(time_t now)
|
||||
iov.iov_base = daemon->dhcp_packet.iov_base;
|
||||
|
||||
/* packet buffer may have moved */
|
||||
mess = daemon->dhcp_packet.iov_base;
|
||||
mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
|
||||
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
dest.sin_len = sizeof(struct sockaddr_in);
|
||||
@@ -262,7 +264,7 @@ void dhcp_packet(time_t now)
|
||||
if (mess->giaddr.s_addr)
|
||||
{
|
||||
/* Send to BOOTP relay */
|
||||
dest.sin_port = htons(DHCP_SERVER_PORT);
|
||||
dest.sin_port = htons(daemon->dhcp_server_port);
|
||||
dest.sin_addr = mess->giaddr;
|
||||
}
|
||||
else if (mess->ciaddr.s_addr)
|
||||
@@ -274,11 +276,11 @@ void dhcp_packet(time_t now)
|
||||
if ((!is_inform && dest.sin_addr.s_addr != mess->ciaddr.s_addr) ||
|
||||
dest.sin_port == 0 || dest.sin_addr.s_addr == 0)
|
||||
{
|
||||
dest.sin_port = htons(DHCP_CLIENT_PORT);
|
||||
dest.sin_port = htons(daemon->dhcp_client_port);
|
||||
dest.sin_addr = mess->ciaddr;
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
else if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
|
||||
mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
|
||||
{
|
||||
@@ -287,14 +289,14 @@ void dhcp_packet(time_t now)
|
||||
msg.msg_control = control_u.control;
|
||||
msg.msg_controllen = sizeof(control_u);
|
||||
cmptr = CMSG_FIRSTHDR(&msg);
|
||||
dest.sin_addr.s_addr = INADDR_BROADCAST;
|
||||
dest.sin_port = htons(DHCP_CLIENT_PORT);
|
||||
pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
|
||||
pkt->ipi_ifindex = iface_index;
|
||||
pkt->ipi_spec_dst.s_addr = 0;
|
||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
||||
cmptr->cmsg_level = SOL_IP;
|
||||
cmptr->cmsg_type = IP_PKTINFO;
|
||||
cmptr->cmsg_type = IP_PKTINFO;
|
||||
dest.sin_addr.s_addr = INADDR_BROADCAST;
|
||||
dest.sin_port = htons(daemon->dhcp_client_port);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -302,7 +304,7 @@ void dhcp_packet(time_t now)
|
||||
struct sockaddr limits size to 14 bytes. */
|
||||
struct arpreq req;
|
||||
dest.sin_addr = mess->yiaddr;
|
||||
dest.sin_port = htons(DHCP_CLIENT_PORT);
|
||||
dest.sin_port = htons(daemon->dhcp_client_port);
|
||||
*((struct sockaddr_in *)&req.arp_pa) = dest;
|
||||
req.arp_ha.sa_family = mess->htype;
|
||||
memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen);
|
||||
@@ -310,7 +312,31 @@ void dhcp_packet(time_t now)
|
||||
req.arp_flags = ATF_COM;
|
||||
ioctl(daemon->dhcpfd, SIOCSARP, &req);
|
||||
}
|
||||
#else
|
||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||
else if ((ntohs(mess->flags) & 0x8000) || mess->hlen != ETHER_ADDR_LEN || mess->htype != ARPHRD_ETHER)
|
||||
{
|
||||
/* broadcast to 255.255.255.255 (or mac address invalid) */
|
||||
dest.sin_addr.s_addr = INADDR_BROADCAST;
|
||||
dest.sin_port = htons(daemon->dhcp_client_port);
|
||||
/* note that we don't specify the interface here: that's done by the
|
||||
IP_XMIT_IF sockopt lower down. */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unicast to unconfigured client. Inject mac address direct into ARP cache.
|
||||
Note that this only works for ethernet on solaris, because we use SIOCSARP
|
||||
and not SIOCSXARP, which would be perfect, except that it returns ENXIO
|
||||
mysteriously. Bah. Fall back to broadcast for other net types. */
|
||||
struct arpreq req;
|
||||
dest.sin_addr = mess->yiaddr;
|
||||
dest.sin_port = htons(daemon->dhcp_client_port);
|
||||
*((struct sockaddr_in *)&req.arp_pa) = dest;
|
||||
req.arp_ha.sa_family = AF_UNSPEC;
|
||||
memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen);
|
||||
req.arp_flags = ATF_COM;
|
||||
ioctl(daemon->dhcpfd, SIOCSARP, &req);
|
||||
}
|
||||
#elif defined(HAVE_BSD_NETWORK)
|
||||
else
|
||||
{
|
||||
send_via_bpf(mess, iov.iov_len, iface_addr, &ifr);
|
||||
@@ -318,6 +344,10 @@ void dhcp_packet(time_t now)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SOLARIS_NETWORK
|
||||
setsockopt(daemon->dhcpfd, IPPROTO_IP, IP_XMIT_IF, &iface_index, sizeof(iface_index));
|
||||
#endif
|
||||
|
||||
while(sendmsg(daemon->dhcpfd, &msg, 0) == -1 && retry_send());
|
||||
}
|
||||
|
||||
@@ -392,7 +422,9 @@ static int complete_context(struct in_addr local, int if_index,
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct dhcp_context *address_available(struct dhcp_context *context, struct in_addr taddr)
|
||||
struct dhcp_context *address_available(struct dhcp_context *context,
|
||||
struct in_addr taddr,
|
||||
struct dhcp_netid *netids)
|
||||
{
|
||||
/* Check is an address is OK for this network, check all
|
||||
possible ranges. Make sure that the address isn't in use
|
||||
@@ -412,14 +444,17 @@ struct dhcp_context *address_available(struct dhcp_context *context, struct in_a
|
||||
|
||||
if (!(tmp->flags & CONTEXT_STATIC) &&
|
||||
addr >= start &&
|
||||
addr <= end)
|
||||
addr <= end &&
|
||||
match_netid(tmp->filter, netids, 1))
|
||||
return tmp;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct dhcp_context *narrow_context(struct dhcp_context *context, struct in_addr taddr)
|
||||
struct dhcp_context *narrow_context(struct dhcp_context *context,
|
||||
struct in_addr taddr,
|
||||
struct dhcp_netid *netids)
|
||||
{
|
||||
/* We start of with a set of possible contexts, all on the current physical interface.
|
||||
These are chained on ->current.
|
||||
@@ -431,19 +466,24 @@ struct dhcp_context *narrow_context(struct dhcp_context *context, struct in_addr
|
||||
|
||||
struct dhcp_context *tmp;
|
||||
|
||||
if ((tmp = address_available(context, taddr)))
|
||||
return tmp;
|
||||
if (!(tmp = address_available(context, taddr, netids)))
|
||||
{
|
||||
for (tmp = context; tmp; tmp = tmp->current)
|
||||
if (is_same_net(taddr, tmp->start, tmp->netmask) &&
|
||||
(tmp->flags & CONTEXT_STATIC))
|
||||
break;
|
||||
|
||||
if (!tmp)
|
||||
for (tmp = context; tmp; tmp = tmp->current)
|
||||
if (is_same_net(taddr, tmp->start, tmp->netmask))
|
||||
break;
|
||||
}
|
||||
|
||||
for (tmp = context; tmp; tmp = tmp->current)
|
||||
if (is_same_net(taddr, tmp->start, tmp->netmask) &&
|
||||
(tmp->flags & CONTEXT_STATIC))
|
||||
return tmp;
|
||||
|
||||
for (tmp = context; tmp; tmp = tmp->current)
|
||||
if (is_same_net(taddr, tmp->start, tmp->netmask))
|
||||
return tmp;
|
||||
|
||||
return NULL;
|
||||
/* Only one context allowed now */
|
||||
if (tmp)
|
||||
tmp->current = NULL;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr)
|
||||
@@ -458,12 +498,12 @@ struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct i
|
||||
}
|
||||
|
||||
/* Is every member of check matched by a member of pool?
|
||||
If negonly, match unless there's a negative tag which matches. */
|
||||
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int negonly)
|
||||
If tagnotneeded, untagged is OK */
|
||||
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int tagnotneeded)
|
||||
{
|
||||
struct dhcp_netid *tmp1;
|
||||
|
||||
if (!check && !negonly)
|
||||
if (!check && !tagnotneeded)
|
||||
return 0;
|
||||
|
||||
for (; check; check = check->next)
|
||||
@@ -473,7 +513,7 @@ int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int negonly)
|
||||
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
|
||||
if (strcmp(check->net, tmp1->net) == 0)
|
||||
break;
|
||||
if (!tmp1 || negonly)
|
||||
if (!tmp1)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
@@ -690,14 +730,14 @@ void dhcp_read_ethers(void)
|
||||
{
|
||||
lineno++;
|
||||
|
||||
while (strlen(buff) > 0 && isspace(buff[strlen(buff)-1]))
|
||||
while (strlen(buff) > 0 && isspace((int)buff[strlen(buff)-1]))
|
||||
buff[strlen(buff)-1] = 0;
|
||||
|
||||
if ((*buff == '#') || (*buff == '+'))
|
||||
continue;
|
||||
|
||||
for (ip = buff; *ip && !isspace(*ip); ip++);
|
||||
for(; *ip && isspace(*ip); ip++)
|
||||
for (ip = buff; *ip && !isspace((int)*ip); ip++);
|
||||
for(; *ip && isspace((int)*ip); ip++)
|
||||
*ip = 0;
|
||||
if (!*ip || parse_hex(buff, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN)
|
||||
{
|
||||
@@ -785,59 +825,44 @@ void dhcp_read_ethers(void)
|
||||
my_syslog(LOG_INFO, _("read %s - %d addresses"), ETHERSFILE, count);
|
||||
}
|
||||
|
||||
void dhcp_read_hosts(void)
|
||||
void check_dhcp_hosts(int fatal)
|
||||
{
|
||||
struct dhcp_config *configs, *cp, **up;
|
||||
int count;
|
||||
|
||||
/* remove existing... */
|
||||
for (up = &daemon->dhcp_conf, configs = daemon->dhcp_conf; configs; configs = cp)
|
||||
{
|
||||
cp = configs->next;
|
||||
|
||||
if (configs->flags & CONFIG_BANK)
|
||||
{
|
||||
if (configs->flags & CONFIG_CLID)
|
||||
free(configs->clid);
|
||||
if (configs->flags & CONFIG_NETID)
|
||||
free(configs->netid.net);
|
||||
if (configs->flags & CONFIG_NAME)
|
||||
free(configs->hostname);
|
||||
|
||||
*up = configs->next;
|
||||
free(configs);
|
||||
}
|
||||
else
|
||||
up = &configs->next;
|
||||
}
|
||||
/* If the same IP appears in more than one host config, then DISCOVER
|
||||
for one of the hosts will get the address, but REQUEST will be NAKed,
|
||||
since the address is reserved by the other one -> protocol loop.
|
||||
Also check that FQDNs match the domain we are using. */
|
||||
|
||||
one_file(daemon->dhcp_hosts_file, 1, 1);
|
||||
|
||||
for (count = 0, configs = daemon->dhcp_conf; configs; configs = configs->next)
|
||||
struct dhcp_config *configs, *cp;
|
||||
|
||||
for (configs = daemon->dhcp_conf; configs; configs = configs->next)
|
||||
{
|
||||
if (configs->flags & CONFIG_BANK)
|
||||
{
|
||||
char *domain;
|
||||
count++;
|
||||
|
||||
for (cp = configs->next; cp; cp = cp->next)
|
||||
if ((configs->flags & cp->flags & CONFIG_ADDR) && configs->addr.s_addr == cp->addr.s_addr)
|
||||
{
|
||||
my_syslog(LOG_ERR, _("duplicate IP address %s in %s."), inet_ntoa(cp->addr), daemon->dhcp_hosts_file);
|
||||
configs->flags &= ~CONFIG_ADDR;
|
||||
}
|
||||
|
||||
if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname)))
|
||||
{
|
||||
my_syslog(LOG_ERR, _("illegal domain %s in %s."), domain, daemon->dhcp_hosts_file);
|
||||
free(configs->hostname);
|
||||
configs->flags &= ~CONFIG_NAME;
|
||||
}
|
||||
}
|
||||
char *domain;
|
||||
|
||||
if ((configs->flags & DHOPT_BANK) || fatal)
|
||||
{
|
||||
for (cp = configs->next; cp; cp = cp->next)
|
||||
if ((configs->flags & cp->flags & CONFIG_ADDR) && configs->addr.s_addr == cp->addr.s_addr)
|
||||
{
|
||||
if (fatal)
|
||||
die(_("duplicate IP address %s in dhcp-config directive."),
|
||||
inet_ntoa(cp->addr), EC_BADCONF);
|
||||
else
|
||||
my_syslog(LOG_ERR, _("duplicate IP address %s in %s."),
|
||||
inet_ntoa(cp->addr), daemon->dhcp_hosts_file);
|
||||
configs->flags &= ~CONFIG_ADDR;
|
||||
}
|
||||
|
||||
if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname)))
|
||||
{
|
||||
if (fatal)
|
||||
die(_("illegal domain %s in dhcp-config directive."), domain, EC_BADCONF);
|
||||
else
|
||||
my_syslog(LOG_ERR, _("illegal domain %s in %s."), domain, daemon->dhcp_hosts_file);
|
||||
free(configs->hostname);
|
||||
configs->flags &= ~CONFIG_NAME;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my_syslog(LOG_INFO, _("read %s - %d hosts"), daemon->dhcp_hosts_file, count);
|
||||
|
||||
}
|
||||
|
||||
void dhcp_update_configs(struct dhcp_config *configs)
|
||||
@@ -856,21 +881,34 @@ void dhcp_update_configs(struct dhcp_config *configs)
|
||||
if (config->flags & CONFIG_ADDR_HOSTS)
|
||||
config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR_HOSTS);
|
||||
|
||||
for (config = configs; config; config = config->next)
|
||||
if (!(config->flags & CONFIG_ADDR) &&
|
||||
(config->flags & CONFIG_NAME) &&
|
||||
(crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) &&
|
||||
(crec->flags & F_HOSTS))
|
||||
{
|
||||
if (config_find_by_address(configs, crec->addr.addr.addr.addr4))
|
||||
my_syslog(LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"),
|
||||
inet_ntoa(crec->addr.addr.addr.addr4), config->hostname);
|
||||
else
|
||||
{
|
||||
config->addr = crec->addr.addr.addr.addr4;
|
||||
config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
|
||||
}
|
||||
}
|
||||
|
||||
if (daemon->port != 0)
|
||||
for (config = configs; config; config = config->next)
|
||||
if (!(config->flags & CONFIG_ADDR) &&
|
||||
(config->flags & CONFIG_NAME) &&
|
||||
(crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) &&
|
||||
(crec->flags & F_HOSTS))
|
||||
{
|
||||
if (cache_find_by_name(crec, config->hostname, 0, F_IPV4))
|
||||
{
|
||||
/* use primary (first) address */
|
||||
while (crec && !(crec->flags & F_REVERSE))
|
||||
crec = cache_find_by_name(crec, config->hostname, 0, F_IPV4);
|
||||
if (!crec)
|
||||
continue; /* should be never */
|
||||
my_syslog(LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"),
|
||||
config->hostname, inet_ntoa(crec->addr.addr.addr.addr4));
|
||||
}
|
||||
|
||||
if (config_find_by_address(configs, crec->addr.addr.addr.addr4))
|
||||
my_syslog(LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"),
|
||||
inet_ntoa(crec->addr.addr.addr.addr4), config->hostname);
|
||||
else
|
||||
{
|
||||
config->addr = crec->addr.addr.addr.addr4;
|
||||
config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If we've not found a hostname any other way, try and see if there's one in /etc/hosts
|
||||
@@ -878,9 +916,13 @@ void dhcp_update_configs(struct dhcp_config *configs)
|
||||
it gets stripped. */
|
||||
char *host_from_dns(struct in_addr addr)
|
||||
{
|
||||
struct crec *lookup = cache_find_by_addr(NULL, (struct all_addr *)&addr, 0, F_IPV4);
|
||||
struct crec *lookup;
|
||||
char *hostname = NULL;
|
||||
|
||||
if (daemon->port == 0)
|
||||
return NULL; /* DNS disabled. */
|
||||
|
||||
lookup = cache_find_by_addr(NULL, (struct all_addr *)&addr, 0, F_IPV4);
|
||||
if (lookup && (lookup->flags & F_HOSTS))
|
||||
{
|
||||
hostname = daemon->dhcp_buff;
|
||||
|
||||
455
src/dnsmasq.c
455
src/dnsmasq.c
@@ -1,13 +1,17 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2006 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991.
|
||||
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
@@ -29,6 +33,9 @@ static char *compile_opts =
|
||||
#ifdef NO_FORK
|
||||
"no-MMU "
|
||||
#endif
|
||||
#ifdef HAVE_BSD_BRIDGE
|
||||
"BSD-bridge "
|
||||
#endif
|
||||
#ifndef HAVE_ISC_READER
|
||||
"no-"
|
||||
#endif
|
||||
@@ -37,7 +44,7 @@ static char *compile_opts =
|
||||
"no-"
|
||||
#endif
|
||||
"DBus "
|
||||
#ifdef NO_GETTEXT
|
||||
#ifndef LOCALEDIR
|
||||
"no-"
|
||||
#endif
|
||||
"I18N "
|
||||
@@ -53,20 +60,29 @@ static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp);
|
||||
static void check_dns_listeners(fd_set *set, time_t now);
|
||||
static void sig_handler(int sig);
|
||||
static void async_event(int pipe, time_t now);
|
||||
static void fatal_event(struct event_desc *ev);
|
||||
static void poll_resolv(void);
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
int bind_fallback = 0;
|
||||
int bad_capabilities = 0;
|
||||
time_t now, last = 0;
|
||||
struct sigaction sigact;
|
||||
struct iname *if_tmp;
|
||||
int piperead, pipefd[2];
|
||||
struct passwd *ent_pw;
|
||||
int piperead, pipefd[2], err_pipe[2];
|
||||
struct passwd *ent_pw = NULL;
|
||||
uid_t script_uid = 0;
|
||||
gid_t script_gid = 0;
|
||||
struct group *gp= NULL;
|
||||
long i, max_fd = sysconf(_SC_OPEN_MAX);
|
||||
char *baduser = NULL;
|
||||
int log_err;
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
cap_user_header_t hdr = NULL;
|
||||
cap_user_data_t data = NULL;
|
||||
#endif
|
||||
|
||||
#ifndef NO_GETTEXT
|
||||
#ifdef LOCALEDIR
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain("dnsmasq", LOCALEDIR);
|
||||
textdomain("dnsmasq");
|
||||
@@ -95,7 +111,7 @@ int main (int argc, char **argv)
|
||||
daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
|
||||
daemon->edns_pktsz : DNSMASQ_PACKETSZ;
|
||||
daemon->packet = safe_malloc(daemon->packet_buff_sz);
|
||||
|
||||
|
||||
if (!daemon->lease_file)
|
||||
{
|
||||
if (daemon->dhcp)
|
||||
@@ -128,6 +144,13 @@ int main (int argc, char **argv)
|
||||
die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SOLARIS_NETWORK
|
||||
if (daemon->max_logs != 0)
|
||||
die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
rand_init();
|
||||
|
||||
now = dnsmasq_time();
|
||||
|
||||
if (daemon->dhcp)
|
||||
@@ -166,11 +189,13 @@ int main (int argc, char **argv)
|
||||
die(_("no interface with address %s"), daemon->namebuff, EC_BADNET);
|
||||
}
|
||||
}
|
||||
else if (!(daemon->listeners = create_wildcard_listeners()))
|
||||
else if ((daemon->port != 0 || (daemon->options & OPT_TFTP)) &&
|
||||
!(daemon->listeners = create_wildcard_listeners()))
|
||||
die(_("failed to create listening socket: %s"), NULL, EC_BADNET);
|
||||
|
||||
cache_init();
|
||||
|
||||
if (daemon->port != 0)
|
||||
cache_init();
|
||||
|
||||
if (daemon->options & OPT_DBUS)
|
||||
#ifdef HAVE_DBUS
|
||||
{
|
||||
@@ -184,60 +209,115 @@ int main (int argc, char **argv)
|
||||
die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
/* If query_port is set then create a socket now, before dumping root
|
||||
for use to access nameservers without more specific source addresses.
|
||||
This allows query_port to be a low port */
|
||||
if (daemon->query_port)
|
||||
if (daemon->port != 0)
|
||||
pre_allocate_sfds();
|
||||
|
||||
/* Note getpwnam returns static storage */
|
||||
if (daemon->dhcp && daemon->lease_change_command && daemon->scriptuser)
|
||||
{
|
||||
union mysockaddr addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.in.sin_family = AF_INET;
|
||||
addr.in.sin_addr.s_addr = INADDR_ANY;
|
||||
addr.in.sin_port = htons(daemon->query_port);
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in.sin_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
allocate_sfd(&addr, &daemon->sfds);
|
||||
#ifdef HAVE_IPV6
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.in6.sin6_family = AF_INET6;
|
||||
addr.in6.sin6_addr = in6addr_any;
|
||||
addr.in6.sin6_port = htons(daemon->query_port);
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in6.sin6_len = sizeof(struct sockaddr_in6);
|
||||
#endif
|
||||
allocate_sfd(&addr, &daemon->sfds);
|
||||
#endif
|
||||
if ((ent_pw = getpwnam(daemon->scriptuser)))
|
||||
{
|
||||
script_uid = ent_pw->pw_uid;
|
||||
script_gid = ent_pw->pw_gid;
|
||||
}
|
||||
else
|
||||
baduser = daemon->scriptuser;
|
||||
}
|
||||
|
||||
if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
|
||||
baduser = daemon->username;
|
||||
else if (daemon->groupname && !(gp = getgrnam(daemon->groupname)))
|
||||
baduser = daemon->groupname;
|
||||
|
||||
if (baduser)
|
||||
die(_("unknown user or group: %s"), baduser, EC_BADCONF);
|
||||
|
||||
/* implement group defaults, "dip" if available, or group associated with uid */
|
||||
if (!daemon->group_set && !gp)
|
||||
{
|
||||
if (!(gp = getgrnam(CHGRP)) && ent_pw)
|
||||
gp = getgrgid(ent_pw->pw_gid);
|
||||
|
||||
/* for error message */
|
||||
if (gp)
|
||||
daemon->groupname = gp->gr_name;
|
||||
}
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
/* determine capability API version here, while we can still
|
||||
call safe_malloc */
|
||||
if (ent_pw && ent_pw->pw_uid != 0)
|
||||
{
|
||||
hdr = safe_malloc(sizeof(*hdr));
|
||||
int capsize = 1; /* for header version 1 */
|
||||
|
||||
/* find version supported by kernel */
|
||||
memset(hdr, 0, sizeof(*hdr));
|
||||
capget(hdr, NULL);
|
||||
|
||||
if (hdr->version != LINUX_CAPABILITY_VERSION_1)
|
||||
{
|
||||
/* if unknown version, use largest supported version (3) */
|
||||
if (hdr->version != LINUX_CAPABILITY_VERSION_2)
|
||||
hdr->version = LINUX_CAPABILITY_VERSION_3;
|
||||
capsize = 2;
|
||||
}
|
||||
|
||||
data = safe_malloc(sizeof(*data) * capsize);
|
||||
memset(data, 0, sizeof(*data) * capsize);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Use a pipe to carry signals and other events back to the event loop
|
||||
in a race-free manner */
|
||||
if (pipe(pipefd) == -1 || !fix_fd(pipefd[0]) || !fix_fd(pipefd[1]))
|
||||
die(_("cannot create pipe: %s"), NULL, EC_MISC);
|
||||
in a race-free manner and another to carry errors to daemon-invoking process */
|
||||
safe_pipe(pipefd, 1);
|
||||
|
||||
piperead = pipefd[0];
|
||||
pipewrite = pipefd[1];
|
||||
/* prime the pipe to load stuff first time. */
|
||||
send_event(pipewrite, EVENT_RELOAD, 0);
|
||||
|
||||
err_pipe[1] = -1;
|
||||
|
||||
if (!(daemon->options & OPT_DEBUG))
|
||||
{
|
||||
FILE *pidfile;
|
||||
int nullfd;
|
||||
|
||||
/* The following code "daemonizes" the process.
|
||||
See Stevens section 12.4 */
|
||||
|
||||
if (chdir("/") != 0)
|
||||
die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
|
||||
|
||||
#ifndef NO_FORK
|
||||
if (!(daemon->options & OPT_NO_FORK))
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
/* pipe to carry errors back to original process.
|
||||
When startup is complete we close this and the process terminates. */
|
||||
safe_pipe(err_pipe, 0);
|
||||
|
||||
if ((pid = fork()) == -1 )
|
||||
die(_("cannot fork into background: %s"), NULL, EC_MISC);
|
||||
|
||||
|
||||
if (pid != 0)
|
||||
_exit(EC_GOOD);
|
||||
{
|
||||
struct event_desc ev;
|
||||
|
||||
/* close our copy of write-end */
|
||||
close(err_pipe[1]);
|
||||
|
||||
/* check for errors after the fork */
|
||||
if (read_write(err_pipe[0], (unsigned char *)&ev, sizeof(ev), 1))
|
||||
fatal_event(&ev);
|
||||
|
||||
_exit(EC_GOOD);
|
||||
}
|
||||
|
||||
close(err_pipe[0]);
|
||||
|
||||
/* NO calls to die() from here on. */
|
||||
|
||||
setsid();
|
||||
pid = fork();
|
||||
@@ -246,16 +326,25 @@ int main (int argc, char **argv)
|
||||
_exit(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
chdir("/");
|
||||
|
||||
/* write pidfile _after_ forking ! */
|
||||
if (daemon->runfile && (pidfile = fopen(daemon->runfile, "w")))
|
||||
{
|
||||
fprintf(pidfile, "%d\n", (int) getpid());
|
||||
fclose(pidfile);
|
||||
if (daemon->runfile)
|
||||
{
|
||||
FILE *pidfile;
|
||||
|
||||
/* only complain if started as root */
|
||||
if ((pidfile = fopen(daemon->runfile, "w")))
|
||||
{
|
||||
fprintf(pidfile, "%d\n", (int) getpid());
|
||||
fclose(pidfile);
|
||||
}
|
||||
else if (getuid() == 0)
|
||||
{
|
||||
send_event(err_pipe[1], EVENT_PIDFILE, errno);
|
||||
_exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* open stdout etc to /dev/null */
|
||||
nullfd = open("/dev/null", O_RDWR);
|
||||
dup2(nullfd, STDOUT_FILENO);
|
||||
@@ -264,65 +353,92 @@ int main (int argc, char **argv)
|
||||
close(nullfd);
|
||||
}
|
||||
|
||||
/* if we are to run scripts, we need to fork a helper before dropping root. */
|
||||
#ifndef NO_FORK
|
||||
daemon->helperfd = create_helper(pipewrite, max_fd);
|
||||
#endif
|
||||
log_err = log_start(ent_pw, err_pipe[1]);
|
||||
|
||||
ent_pw = daemon->username ? getpwnam(daemon->username) : NULL;
|
||||
/* if we are to run scripts, we need to fork a helper before dropping root. */
|
||||
daemon->helperfd = -1;
|
||||
#ifndef NO_FORK
|
||||
if (daemon->dhcp && daemon->lease_change_command)
|
||||
daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
|
||||
#endif
|
||||
|
||||
/* before here, we should only call die(), after here, only call syslog() */
|
||||
log_start(ent_pw);
|
||||
|
||||
if (!(daemon->options & OPT_DEBUG))
|
||||
if (!(daemon->options & OPT_DEBUG) && getuid() == 0)
|
||||
{
|
||||
/* UID changing, etc */
|
||||
if (daemon->groupname || ent_pw)
|
||||
{
|
||||
gid_t dummy;
|
||||
struct group *gp;
|
||||
|
||||
/* change group for /etc/ppp/resolv.conf otherwise get the group for "nobody" */
|
||||
if ((daemon->groupname && (gp = getgrnam(daemon->groupname))) ||
|
||||
(ent_pw && (gp = getgrgid(ent_pw->pw_gid))))
|
||||
{
|
||||
/* remove all supplimentary groups */
|
||||
setgroups(0, &dummy);
|
||||
setgid(gp->gr_gid);
|
||||
}
|
||||
}
|
||||
int bad_capabilities = 0;
|
||||
gid_t dummy;
|
||||
|
||||
/* remove all supplimentary groups */
|
||||
if (gp &&
|
||||
(setgroups(0, &dummy) == -1 ||
|
||||
setgid(gp->gr_gid) == -1))
|
||||
{
|
||||
send_event(err_pipe[1], EVENT_GROUP_ERR, errno);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
if (ent_pw && ent_pw->pw_uid != 0)
|
||||
{
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
/* On linux, we keep CAP_NETADMIN (for ARP-injection) and
|
||||
CAP_NET_RAW (for icmp) if we're doing dhcp */
|
||||
cap_user_header_t hdr = safe_malloc(sizeof(*hdr));
|
||||
cap_user_data_t data = safe_malloc(sizeof(*data));
|
||||
hdr->version = _LINUX_CAPABILITY_VERSION;
|
||||
hdr->pid = 0; /* this process */
|
||||
data->effective = data->permitted = data->inheritable =
|
||||
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
|
||||
(1 << CAP_SETGID) | (1 << CAP_SETUID);
|
||||
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
|
||||
|
||||
/* Tell kernel to not clear capabilities when dropping root */
|
||||
if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1) == -1)
|
||||
bad_capabilities = errno;
|
||||
else
|
||||
#endif
|
||||
|
||||
#elif defined(HAVE_SOLARIS_PRIVS)
|
||||
/* http://developers.sun.com/solaris/articles/program_privileges.html */
|
||||
priv_set_t *priv_set;
|
||||
|
||||
if (!(priv_set = priv_str_to_set("basic", ",", NULL)) ||
|
||||
priv_addset(priv_set, PRIV_NET_ICMPACCESS) == -1 ||
|
||||
priv_addset(priv_set, PRIV_SYS_NET_CONFIG) == -1)
|
||||
bad_capabilities = errno;
|
||||
|
||||
if (priv_set && bad_capabilities == 0)
|
||||
{
|
||||
/* finally drop root */
|
||||
setuid(ent_pw->pw_uid);
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
data->effective = data->permitted =
|
||||
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
|
||||
data->inheritable = 0;
|
||||
|
||||
/* lose the setuid and setgid capbilities */
|
||||
capset(hdr, data);
|
||||
#endif
|
||||
priv_inverse(priv_set);
|
||||
|
||||
if (setppriv(PRIV_OFF, PRIV_LIMIT, priv_set) == -1)
|
||||
bad_capabilities = errno;
|
||||
}
|
||||
|
||||
if (priv_set)
|
||||
priv_freeset(priv_set);
|
||||
|
||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||
|
||||
bad_capabilities = ENOTSUP;
|
||||
#endif
|
||||
|
||||
if (bad_capabilities != 0)
|
||||
{
|
||||
send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
/* finally drop root */
|
||||
if (setuid(ent_pw->pw_uid) == -1)
|
||||
{
|
||||
send_event(err_pipe[1], EVENT_USER_ERR, errno);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
data->effective = data->permitted =
|
||||
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
|
||||
data->inheritable = 0;
|
||||
|
||||
/* lose the setuid and setgid capbilities */
|
||||
if (capset(hdr, data) == -1)
|
||||
{
|
||||
send_event(err_pipe[1], EVENT_CAP_ERR, errno);
|
||||
_exit(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,7 +447,9 @@ int main (int argc, char **argv)
|
||||
prctl(PR_SET_DUMPABLE, 1);
|
||||
#endif
|
||||
|
||||
if (daemon->cachesize != 0)
|
||||
if (daemon->port == 0)
|
||||
my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
|
||||
else if (daemon->cachesize != 0)
|
||||
my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
|
||||
else
|
||||
my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
|
||||
@@ -348,6 +466,10 @@ int main (int argc, char **argv)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (log_err != 0)
|
||||
my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
|
||||
daemon->log_file, strerror(log_err));
|
||||
|
||||
if (bind_fallback)
|
||||
my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
|
||||
|
||||
@@ -356,7 +478,7 @@ int main (int argc, char **argv)
|
||||
if (if_tmp->name && !if_tmp->used)
|
||||
my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
|
||||
|
||||
if (daemon->options & OPT_NO_RESOLV)
|
||||
if (daemon->port != 0 && (daemon->options & OPT_NO_RESOLV))
|
||||
{
|
||||
if (daemon->resolv_files && !daemon->resolv_files->is_default)
|
||||
my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
|
||||
@@ -410,6 +532,12 @@ int main (int argc, char **argv)
|
||||
max_fd = max_fd/2;
|
||||
else
|
||||
max_fd = max_fd - 20;
|
||||
|
||||
/* if we have to use a limited range of ports,
|
||||
that will limit the number of transfers */
|
||||
if (daemon->start_tftp_port != 0 &&
|
||||
daemon->end_tftp_port - daemon->start_tftp_port + 1 < max_fd)
|
||||
max_fd = daemon->end_tftp_port - daemon->start_tftp_port + 1;
|
||||
|
||||
if (daemon->tftp_max > max_fd)
|
||||
{
|
||||
@@ -421,16 +549,13 @@ int main (int argc, char **argv)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!(daemon->options & OPT_DEBUG) && (getuid() == 0 || geteuid() == 0))
|
||||
{
|
||||
if (bad_capabilities)
|
||||
my_syslog(LOG_WARNING, _("warning: setting capabilities failed: %s"), strerror(bad_capabilities));
|
||||
|
||||
my_syslog(LOG_WARNING, _("running as root"));
|
||||
}
|
||||
/* finished start-up - release original process */
|
||||
if (err_pipe[1] != -1)
|
||||
close(err_pipe[1]);
|
||||
|
||||
if (daemon->port != 0)
|
||||
check_servers();
|
||||
|
||||
check_servers();
|
||||
|
||||
pid = getpid();
|
||||
|
||||
while (1)
|
||||
@@ -517,7 +642,7 @@ int main (int argc, char **argv)
|
||||
load_dhcp(now);
|
||||
#endif
|
||||
|
||||
if (!(daemon->options & OPT_NO_POLL))
|
||||
if (daemon->port != 0 && !(daemon->options & OPT_NO_POLL))
|
||||
poll_resolv();
|
||||
}
|
||||
|
||||
@@ -541,7 +666,7 @@ int main (int argc, char **argv)
|
||||
}
|
||||
check_dbus_listeners(&rset, &wset, &eset);
|
||||
#endif
|
||||
|
||||
|
||||
check_dns_listeners(&rset, now);
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
@@ -605,11 +730,48 @@ void send_event(int fd, int event, int data)
|
||||
|
||||
ev.event = event;
|
||||
ev.data = data;
|
||||
/* pipe is non-blocking and struct event_desc is smaller than
|
||||
PIPE_BUF, so this either fails or writes everything */
|
||||
while (write(fd, &ev, sizeof(ev)) == -1 && errno == EINTR);
|
||||
|
||||
/* error pipe, debug mode. */
|
||||
if (fd == -1)
|
||||
fatal_event(&ev);
|
||||
else
|
||||
/* pipe is non-blocking and struct event_desc is smaller than
|
||||
PIPE_BUF, so this either fails or writes everything */
|
||||
while (write(fd, &ev, sizeof(ev)) == -1 && errno == EINTR);
|
||||
}
|
||||
|
||||
static void fatal_event(struct event_desc *ev)
|
||||
{
|
||||
errno = ev->data;
|
||||
|
||||
switch (ev->event)
|
||||
{
|
||||
case EVENT_DIE:
|
||||
exit(0);
|
||||
|
||||
case EVENT_PIPE_ERR:
|
||||
die(_("failed to create helper: %s"), NULL, EC_MISC);
|
||||
|
||||
case EVENT_CAP_ERR:
|
||||
die(_("setting capabilities failed: %s"), NULL, EC_MISC);
|
||||
|
||||
case EVENT_USER_ERR:
|
||||
case EVENT_HUSER_ERR:
|
||||
die(_("failed to change user-id to %s: %s"),
|
||||
ev->event == EVENT_USER_ERR ? daemon->username : daemon->scriptuser,
|
||||
EC_MISC);
|
||||
|
||||
case EVENT_GROUP_ERR:
|
||||
die(_("failed to change group-id to %s: %s"), daemon->groupname, EC_MISC);
|
||||
|
||||
case EVENT_PIDFILE:
|
||||
die(_("failed to open pidfile %s: %s"), daemon->runfile, EC_FILE);
|
||||
|
||||
case EVENT_LOG_ERR:
|
||||
die(_("cannot open %s: %s"), daemon->log_file ? daemon->log_file : "log", EC_FILE);
|
||||
}
|
||||
}
|
||||
|
||||
static void async_event(int pipe, time_t now)
|
||||
{
|
||||
pid_t p;
|
||||
@@ -621,7 +783,7 @@ static void async_event(int pipe, time_t now)
|
||||
{
|
||||
case EVENT_RELOAD:
|
||||
clear_cache_and_reload(now);
|
||||
if (daemon->resolv_files && (daemon->options & OPT_NO_POLL))
|
||||
if (daemon->port != 0 && daemon->resolv_files && (daemon->options & OPT_NO_POLL))
|
||||
{
|
||||
reload_servers(daemon->resolv_files->name);
|
||||
check_servers();
|
||||
@@ -630,7 +792,8 @@ static void async_event(int pipe, time_t now)
|
||||
break;
|
||||
|
||||
case EVENT_DUMP:
|
||||
dump_cache(now);
|
||||
if (daemon->port != 0)
|
||||
dump_cache(now);
|
||||
break;
|
||||
|
||||
case EVENT_ALARM:
|
||||
@@ -664,11 +827,14 @@ static void async_event(int pipe, time_t now)
|
||||
break;
|
||||
|
||||
case EVENT_EXEC_ERR:
|
||||
my_syslog(LOG_ERR, _("failed to execute %s: %s"), daemon->lease_change_command, strerror(ev.data));
|
||||
my_syslog(LOG_ERR, _("failed to execute %s: %s"),
|
||||
daemon->lease_change_command, strerror(ev.data));
|
||||
break;
|
||||
|
||||
case EVENT_PIPE_ERR:
|
||||
my_syslog(LOG_ERR, _("failed to create helper: %s"), strerror(ev.data));
|
||||
/* necessary for fatal errors in helper */
|
||||
case EVENT_HUSER_ERR:
|
||||
case EVENT_DIE:
|
||||
fatal_event(&ev);
|
||||
break;
|
||||
|
||||
case EVENT_REOPEN:
|
||||
@@ -762,14 +928,16 @@ static void poll_resolv()
|
||||
|
||||
void clear_cache_and_reload(time_t now)
|
||||
{
|
||||
cache_reload(daemon->options, daemon->namebuff, daemon->domain_suffix, daemon->addn_hosts);
|
||||
if (daemon->port != 0)
|
||||
cache_reload(daemon->options, daemon->namebuff, daemon->domain_suffix, daemon->addn_hosts);
|
||||
|
||||
if (daemon->dhcp)
|
||||
{
|
||||
if (daemon->options & OPT_ETHERS)
|
||||
dhcp_read_ethers();
|
||||
if (daemon->dhcp_hosts_file)
|
||||
dhcp_read_hosts();
|
||||
reread_dhcp();
|
||||
dhcp_update_configs(daemon->dhcp_conf);
|
||||
check_dhcp_hosts(0);
|
||||
lease_update_from_configs();
|
||||
lease_update_file(now);
|
||||
lease_update_dns();
|
||||
@@ -780,7 +948,7 @@ static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
|
||||
{
|
||||
struct serverfd *serverfdp;
|
||||
struct listener *listener;
|
||||
int wait, i;
|
||||
int wait = 0, i;
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
int tftp = 0;
|
||||
@@ -794,18 +962,27 @@ static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
|
||||
#endif
|
||||
|
||||
/* will we be able to get memory? */
|
||||
get_new_frec(now, &wait);
|
||||
if (daemon->port != 0)
|
||||
get_new_frec(now, &wait);
|
||||
|
||||
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
|
||||
{
|
||||
FD_SET(serverfdp->fd, set);
|
||||
bump_maxfd(serverfdp->fd, maxfdp);
|
||||
}
|
||||
|
||||
|
||||
if (daemon->port != 0 && !daemon->osport)
|
||||
for (i = 0; i < RANDOM_SOCKS; i++)
|
||||
if (daemon->randomsocks[i].refcount != 0)
|
||||
{
|
||||
FD_SET(daemon->randomsocks[i].fd, set);
|
||||
bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
|
||||
}
|
||||
|
||||
for (listener = daemon->listeners; listener; listener = listener->next)
|
||||
{
|
||||
/* only listen for queries if we have resources */
|
||||
if (wait == 0)
|
||||
if (listener->fd != -1 && wait == 0)
|
||||
{
|
||||
FD_SET(listener->fd, set);
|
||||
bump_maxfd(listener->fd, maxfdp);
|
||||
@@ -813,13 +990,14 @@ static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
|
||||
|
||||
/* death of a child goes through the select loop, so
|
||||
we don't need to explicitly arrange to wake up here */
|
||||
for (i = 0; i < MAX_PROCS; i++)
|
||||
if (daemon->tcp_pids[i] == 0)
|
||||
{
|
||||
FD_SET(listener->tcpfd, set);
|
||||
bump_maxfd(listener->tcpfd, maxfdp);
|
||||
break;
|
||||
}
|
||||
if (listener->tcpfd != -1)
|
||||
for (i = 0; i < MAX_PROCS; i++)
|
||||
if (daemon->tcp_pids[i] == 0)
|
||||
{
|
||||
FD_SET(listener->tcpfd, set);
|
||||
bump_maxfd(listener->tcpfd, maxfdp);
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
|
||||
@@ -837,23 +1015,30 @@ static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
|
||||
static void check_dns_listeners(fd_set *set, time_t now)
|
||||
{
|
||||
struct serverfd *serverfdp;
|
||||
struct listener *listener;
|
||||
|
||||
struct listener *listener;
|
||||
int i;
|
||||
|
||||
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
|
||||
if (FD_ISSET(serverfdp->fd, set))
|
||||
reply_query(serverfdp, now);
|
||||
reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
|
||||
|
||||
if (daemon->port != 0 && !daemon->osport)
|
||||
for (i = 0; i < RANDOM_SOCKS; i++)
|
||||
if (daemon->randomsocks[i].refcount != 0 &&
|
||||
FD_ISSET(daemon->randomsocks[i].fd, set))
|
||||
reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
|
||||
|
||||
for (listener = daemon->listeners; listener; listener = listener->next)
|
||||
{
|
||||
if (FD_ISSET(listener->fd, set))
|
||||
if (listener->fd != -1 && FD_ISSET(listener->fd, set))
|
||||
receive_query(listener, now);
|
||||
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
|
||||
tftp_request(listener, now);
|
||||
#endif
|
||||
|
||||
if (FD_ISSET(listener->tcpfd, set))
|
||||
if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
|
||||
{
|
||||
int confd;
|
||||
struct irec *iface = NULL;
|
||||
@@ -997,7 +1182,7 @@ int icmp_ping(struct in_addr addr)
|
||||
int gotreply = 0;
|
||||
time_t start, now;
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
#if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
|
||||
if ((fd = make_icmp_sock()) == -1)
|
||||
return 0;
|
||||
#else
|
||||
@@ -1072,7 +1257,7 @@ int icmp_ping(struct in_addr addr)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
|
||||
close(fd);
|
||||
#else
|
||||
opt = 1;
|
||||
|
||||
215
src/dnsmasq.h
215
src/dnsmasq.h
@@ -1,16 +1,32 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
|
||||
|
||||
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991.
|
||||
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define COPYRIGHT "Copyright (C) 2000-2007 Simon Kelley"
|
||||
#define COPYRIGHT "Copyright (C) 2000-2008 Simon Kelley"
|
||||
|
||||
#ifndef NO_LARGEFILE
|
||||
/* Ensure we can use files >2GB (log files may grow this big) */
|
||||
# define _LARGEFILE_SOURCE 1
|
||||
# define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
|
||||
/* Get linux C library versions. */
|
||||
#ifdef __linux__
|
||||
# define _GNU_SOURCE
|
||||
# include <features.h>
|
||||
#endif
|
||||
|
||||
/* get these before config.h for IPv6 stuff... */
|
||||
#include <sys/types.h>
|
||||
@@ -28,7 +44,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#define gettext_noop(S) (S)
|
||||
#ifdef NO_GETTEXT
|
||||
#ifndef LOCALEDIR
|
||||
# define _(S) (S)
|
||||
#else
|
||||
# include <libintl.h>
|
||||
@@ -40,6 +56,9 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#if defined(HAVE_SOLARIS_NETWORK)
|
||||
#include <sys/sockio.h>
|
||||
#endif
|
||||
#include <sys/select.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/time.h>
|
||||
@@ -53,12 +72,13 @@
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
#include <signal.h>
|
||||
#include <stddef.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <stdarg.h>
|
||||
#if defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__sun__) || defined (__sun)
|
||||
# include <netinet/if_ether.h>
|
||||
#else
|
||||
# include <net/ethernet.h>
|
||||
@@ -74,15 +94,22 @@
|
||||
# include <net/if_dl.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
#include <linux/capability.h>
|
||||
/* There doesn't seem to be a universally-available
|
||||
userpace header for this. */
|
||||
userpace header for these. */
|
||||
extern int capset(cap_user_header_t header, cap_user_data_t data);
|
||||
extern int capget(cap_user_header_t header, cap_user_data_t data);
|
||||
#define LINUX_CAPABILITY_VERSION_1 0x19980330
|
||||
#define LINUX_CAPABILITY_VERSION_2 0x20071026
|
||||
#define LINUX_CAPABILITY_VERSION_3 0x20080522
|
||||
|
||||
#include <sys/prctl.h>
|
||||
#elif defined(HAVE_SOLARIS_PRIVS)
|
||||
#include <priv.h>
|
||||
#endif
|
||||
|
||||
/* daemon is function in teh C library.... */
|
||||
/* daemon is function in the C library.... */
|
||||
#define daemon dnsmasq_daemon
|
||||
|
||||
/* Async event queue */
|
||||
@@ -100,6 +127,13 @@ struct event_desc {
|
||||
#define EVENT_KILLED 8
|
||||
#define EVENT_EXEC_ERR 9
|
||||
#define EVENT_PIPE_ERR 10
|
||||
#define EVENT_USER_ERR 11
|
||||
#define EVENT_CAP_ERR 12
|
||||
#define EVENT_PIDFILE 13
|
||||
#define EVENT_HUSER_ERR 14
|
||||
#define EVENT_GROUP_ERR 15
|
||||
#define EVENT_DIE 16
|
||||
#define EVENT_LOG_ERR 17
|
||||
|
||||
/* Exit codes. */
|
||||
#define EC_GOOD 0
|
||||
@@ -117,35 +151,38 @@ struct event_desc {
|
||||
*/
|
||||
#define DNSMASQ_PACKETSZ PACKETSZ+MAXDNAME+RRFIXEDSZ
|
||||
|
||||
#define OPT_BOGUSPRIV (1<<0)
|
||||
#define OPT_FILTER (1<<1)
|
||||
#define OPT_LOG (1<<2)
|
||||
#define OPT_SELFMX (1<<3)
|
||||
#define OPT_NO_HOSTS (1<<4)
|
||||
#define OPT_NO_POLL (1<<5)
|
||||
#define OPT_DEBUG (1<<6)
|
||||
#define OPT_ORDER (1<<7)
|
||||
#define OPT_NO_RESOLV (1<<8)
|
||||
#define OPT_EXPAND (1<<9)
|
||||
#define OPT_LOCALMX (1<<10)
|
||||
#define OPT_NO_NEG (1<<11)
|
||||
#define OPT_NODOTS_LOCAL (1<<12)
|
||||
#define OPT_NOWILD (1<<13)
|
||||
#define OPT_ETHERS (1<<14)
|
||||
#define OPT_RESOLV_DOMAIN (1<<15)
|
||||
#define OPT_NO_FORK (1<<16)
|
||||
#define OPT_AUTHORITATIVE (1<<17)
|
||||
#define OPT_LOCALISE (1<<18)
|
||||
#define OPT_DBUS (1<<19)
|
||||
#define OPT_BOOTP_DYNAMIC (1<<20)
|
||||
#define OPT_NO_PING (1<<21)
|
||||
#define OPT_LEASE_RO (1<<22)
|
||||
#define OPT_RELOAD (1<<24)
|
||||
#define OPT_TFTP (1<<25)
|
||||
#define OPT_TFTP_SECURE (1<<26)
|
||||
#define OPT_TFTP_NOBLOCK (1<<27)
|
||||
#define OPT_LOG_OPTS (1<<28)
|
||||
#define OPT_TFTP_APREF (1<<29)
|
||||
#define OPT_BOGUSPRIV (1u<<0)
|
||||
#define OPT_FILTER (1u<<1)
|
||||
#define OPT_LOG (1u<<2)
|
||||
#define OPT_SELFMX (1u<<3)
|
||||
#define OPT_NO_HOSTS (1u<<4)
|
||||
#define OPT_NO_POLL (1u<<5)
|
||||
#define OPT_DEBUG (1u<<6)
|
||||
#define OPT_ORDER (1u<<7)
|
||||
#define OPT_NO_RESOLV (1u<<8)
|
||||
#define OPT_EXPAND (1u<<9)
|
||||
#define OPT_LOCALMX (1u<<10)
|
||||
#define OPT_NO_NEG (1u<<11)
|
||||
#define OPT_NODOTS_LOCAL (1u<<12)
|
||||
#define OPT_NOWILD (1u<<13)
|
||||
#define OPT_ETHERS (1u<<14)
|
||||
#define OPT_RESOLV_DOMAIN (1u<<15)
|
||||
#define OPT_NO_FORK (1u<<16)
|
||||
#define OPT_AUTHORITATIVE (1u<<17)
|
||||
#define OPT_LOCALISE (1u<<18)
|
||||
#define OPT_DBUS (1u<<19)
|
||||
#define OPT_BOOTP_DYNAMIC (1u<<20)
|
||||
#define OPT_NO_PING (1u<<21)
|
||||
#define OPT_LEASE_RO (1u<<22)
|
||||
#define OPT_ALL_SERVERS (1u<<23)
|
||||
#define OPT_RELOAD (1u<<24)
|
||||
#define OPT_TFTP (1u<<25)
|
||||
#define OPT_TFTP_SECURE (1u<<26)
|
||||
#define OPT_TFTP_NOBLOCK (1u<<27)
|
||||
#define OPT_LOG_OPTS (1u<<28)
|
||||
#define OPT_TFTP_APREF (1u<<29)
|
||||
#define OPT_NO_OVERRIDE (1u<<30)
|
||||
#define OPT_NO_REBIND (1u<<31)
|
||||
|
||||
struct all_addr {
|
||||
union {
|
||||
@@ -174,6 +211,12 @@ struct mx_srv_record {
|
||||
struct mx_srv_record *next;
|
||||
};
|
||||
|
||||
struct naptr {
|
||||
char *name, *replace, *regexp, *services, *flags;
|
||||
unsigned int order, pref;
|
||||
struct naptr *next;
|
||||
};
|
||||
|
||||
struct txt_record {
|
||||
char *name, *txt;
|
||||
unsigned short class, len;
|
||||
@@ -265,18 +308,27 @@ union mysockaddr {
|
||||
#define SERV_FROM_DBUS 128 /* 1 if source is DBus */
|
||||
#define SERV_MARK 256 /* for mark-and-delete */
|
||||
#define SERV_TYPE (SERV_HAS_DOMAIN | SERV_FOR_NODOTS)
|
||||
#define SERV_COUNTED 512 /* workspace for log code */
|
||||
|
||||
struct serverfd {
|
||||
int fd;
|
||||
union mysockaddr source_addr;
|
||||
char interface[IF_NAMESIZE+1];
|
||||
struct serverfd *next;
|
||||
};
|
||||
|
||||
struct randfd {
|
||||
int fd;
|
||||
unsigned short refcount, family;
|
||||
};
|
||||
|
||||
struct server {
|
||||
union mysockaddr addr, source_addr;
|
||||
char interface[IF_NAMESIZE+1];
|
||||
struct serverfd *sfd;
|
||||
char *domain; /* set if this server only handles a domain. */
|
||||
int flags, tcpfd;
|
||||
unsigned int queries, failed_queries;
|
||||
struct server *next;
|
||||
};
|
||||
|
||||
@@ -320,6 +372,10 @@ struct frec {
|
||||
union mysockaddr source;
|
||||
struct all_addr dest;
|
||||
struct server *sentto; /* NULL means free */
|
||||
struct randfd *rfd4;
|
||||
#ifdef HAVE_IPV6
|
||||
struct randfd *rfd6;
|
||||
#endif
|
||||
unsigned int iface;
|
||||
unsigned short orig_id, new_id;
|
||||
int fd, forwardall;
|
||||
@@ -351,9 +407,10 @@ struct dhcp_lease {
|
||||
#endif
|
||||
int hwaddr_len, hwaddr_type;
|
||||
unsigned char hwaddr[DHCP_CHADDR_MAX];
|
||||
struct in_addr addr;
|
||||
struct in_addr addr, override;
|
||||
unsigned char *vendorclass, *userclass;
|
||||
unsigned int vendorclass_len, userclass_len;
|
||||
int last_interface;
|
||||
struct dhcp_lease *next;
|
||||
};
|
||||
|
||||
@@ -406,6 +463,7 @@ struct dhcp_opt {
|
||||
#define DHOPT_ENCAPSULATE 4
|
||||
#define DHOPT_VENDOR_MATCH 8
|
||||
#define DHOPT_FORCE 16
|
||||
#define DHOPT_BANK 32
|
||||
|
||||
struct dhcp_boot {
|
||||
char *file, *sname;
|
||||
@@ -419,10 +477,11 @@ struct dhcp_boot {
|
||||
#define MATCH_CIRCUIT 3
|
||||
#define MATCH_REMOTE 4
|
||||
#define MATCH_SUBSCRIBER 5
|
||||
#define MATCH_OPTION 6
|
||||
|
||||
/* vendorclass, userclass, remote-id or cicuit-id */
|
||||
struct dhcp_vendor {
|
||||
int len, match_type;
|
||||
int len, match_type, option;
|
||||
char *data;
|
||||
struct dhcp_netid netid;
|
||||
struct dhcp_vendor *next;
|
||||
@@ -436,7 +495,7 @@ struct dhcp_mac {
|
||||
struct dhcp_mac *next;
|
||||
};
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
#ifdef HAVE_BSD_BRIDGE
|
||||
struct dhcp_bridge {
|
||||
char iface[IF_NAMESIZE];
|
||||
struct dhcp_bridge *alias, *next;
|
||||
@@ -490,9 +549,10 @@ struct tftp_transfer {
|
||||
int sockfd;
|
||||
time_t timeout;
|
||||
int backoff;
|
||||
unsigned int block, blocksize;
|
||||
unsigned int block, blocksize, expansion;
|
||||
off_t offset;
|
||||
struct sockaddr_in peer;
|
||||
char opt_blocksize, opt_transize;
|
||||
char opt_blocksize, opt_transize, netascii, carrylf;
|
||||
struct tftp_file *file;
|
||||
struct tftp_transfer *next;
|
||||
};
|
||||
@@ -505,12 +565,14 @@ extern struct daemon {
|
||||
unsigned int options;
|
||||
struct resolvc default_resolv, *resolv_files;
|
||||
struct mx_srv_record *mxnames;
|
||||
struct naptr *naptr;
|
||||
struct txt_record *txt;
|
||||
struct ptr_record *ptr;
|
||||
struct interface_name *int_names;
|
||||
char *mxtarget;
|
||||
char *lease_file;
|
||||
char *username, *groupname;
|
||||
char *username, *groupname, *scriptuser;
|
||||
int group_set, osport;
|
||||
char *domain_suffix;
|
||||
char *runfile;
|
||||
char *lease_change_command;
|
||||
@@ -521,8 +583,8 @@ extern struct daemon {
|
||||
char *log_file; /* optional log file */
|
||||
int max_logs; /* queue limit */
|
||||
int cachesize, ftabsize;
|
||||
int port, query_port;
|
||||
unsigned long local_ttl;
|
||||
int port, query_port, min_port;
|
||||
unsigned long local_ttl, neg_ttl;
|
||||
struct hostsfile *addn_hosts;
|
||||
struct dhcp_context *dhcp;
|
||||
struct dhcp_config *dhcp_conf;
|
||||
@@ -530,17 +592,22 @@ extern struct daemon {
|
||||
struct dhcp_vendor *dhcp_vendors;
|
||||
struct dhcp_mac *dhcp_macs;
|
||||
struct dhcp_boot *boot_config;
|
||||
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names;
|
||||
char *dhcp_hosts_file;
|
||||
int dhcp_max, tftp_max;
|
||||
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *force_broadcast;
|
||||
char *dhcp_hosts_file, *dhcp_opts_file;
|
||||
int dhcp_max, tftp_max;
|
||||
int dhcp_server_port, dhcp_client_port;
|
||||
int start_tftp_port, end_tftp_port;
|
||||
unsigned int min_leasetime;
|
||||
struct doctor *doctors;
|
||||
unsigned short edns_pktsz;
|
||||
char *tftp_prefix;
|
||||
|
||||
/* globally used stuff for DNS */
|
||||
char *packet; /* packet buffer */
|
||||
int packet_buff_sz; /* size of above */
|
||||
char *namebuff; /* MAXDNAME size buffer */
|
||||
unsigned int local_answer, queries_forwarded;
|
||||
struct frec *frec_list;
|
||||
struct serverfd *sfds;
|
||||
struct irec *interfaces;
|
||||
struct listener *listeners;
|
||||
@@ -548,7 +615,8 @@ extern struct daemon {
|
||||
struct server *srv_save; /* Used for resend on DoD */
|
||||
size_t packet_len; /* " " */
|
||||
pid_t tcp_pids[MAX_PROCS];
|
||||
|
||||
struct randfd randomsocks[RANDOM_SOCKS];
|
||||
|
||||
/* DHCP state */
|
||||
int dhcpfd, helperfd;
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
@@ -560,7 +628,7 @@ extern struct daemon {
|
||||
char *dhcp_buff, *dhcp_buff2;
|
||||
struct ping_result *ping_results;
|
||||
FILE *lease_stream;
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
#ifdef HAVE_BSD_BRIDGE
|
||||
struct dhcp_bridge *bridges;
|
||||
#endif
|
||||
|
||||
@@ -573,13 +641,14 @@ extern struct daemon {
|
||||
|
||||
/* TFTP stuff */
|
||||
struct tftp_transfer *tftp_trans;
|
||||
char *tftp_prefix;
|
||||
|
||||
} *daemon;
|
||||
|
||||
/* cache.c */
|
||||
void cache_init(void);
|
||||
void log_query(unsigned short flags, char *name, struct all_addr *addr,
|
||||
unsigned short type, struct hostsfile *addn_hosts, int index);
|
||||
void log_query(unsigned short flags, char *name, struct all_addr *addr, char *arg);
|
||||
char *record_source(struct hostsfile *addn_hosts, int index);
|
||||
void querystr(char *str, unsigned short type);
|
||||
struct crec *cache_find_by_addr(struct crec *crecp,
|
||||
struct all_addr *addr, time_t now,
|
||||
unsigned short prot);
|
||||
@@ -601,7 +670,7 @@ unsigned short extract_request(HEADER *header, size_t qlen,
|
||||
size_t setup_reply(HEADER *header, size_t qlen,
|
||||
struct all_addr *addrp, unsigned short flags,
|
||||
unsigned long local_ttl);
|
||||
void extract_addresses(HEADER *header, size_t qlen, char *namebuff, time_t now);
|
||||
int extract_addresses(HEADER *header, size_t qlen, char *namebuff, time_t now);
|
||||
size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
struct in_addr local_addr, struct in_addr local_netmask, time_t now);
|
||||
int check_for_bogus_wildcard(HEADER *header, size_t qlen, char *name,
|
||||
@@ -614,11 +683,13 @@ size_t resize_packet(HEADER *header, size_t plen,
|
||||
unsigned char *pheader, size_t hlen);
|
||||
|
||||
/* util.c */
|
||||
void rand_init(void);
|
||||
unsigned short rand16(void);
|
||||
int legal_char(char c);
|
||||
int canonicalise(char *s);
|
||||
unsigned char *do_rfc1035_name(unsigned char *p, char *sval);
|
||||
void *safe_malloc(size_t size);
|
||||
void safe_pipe(int *fd, int read_noblock);
|
||||
void *whine_malloc(size_t size);
|
||||
int sa_len(union mysockaddr *addr);
|
||||
int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
|
||||
@@ -639,7 +710,7 @@ int read_write(int fd, unsigned char *packet, int size, int rw);
|
||||
|
||||
/* log.c */
|
||||
void die(char *message, char *arg1, int exit_code);
|
||||
void log_start(struct passwd *ent_pw);
|
||||
int log_start(struct passwd *ent_pw, int errfd);
|
||||
int log_reopen(char *log_file);
|
||||
void my_syslog(int priority, const char *format, ...);
|
||||
void set_log_writer(fd_set *set, int *maxfdp);
|
||||
@@ -649,10 +720,10 @@ void flush_log(void);
|
||||
/* option.c */
|
||||
void read_opts (int argc, char **argv, char *compile_opts);
|
||||
char *option_string(unsigned char opt);
|
||||
void one_file(char *file, int nest, int hosts);
|
||||
void reread_dhcp(void);
|
||||
|
||||
/* forward.c */
|
||||
void reply_query(struct serverfd *sfd, time_t now);
|
||||
void reply_query(int fd, int family, time_t now);
|
||||
void receive_query(struct listener *listen, time_t now);
|
||||
unsigned char *tcp_request(int confd, time_t now,
|
||||
struct in_addr local_addr, struct in_addr netmask);
|
||||
@@ -660,7 +731,9 @@ void server_gone(struct server *server);
|
||||
struct frec *get_new_frec(time_t now, int *wait);
|
||||
|
||||
/* network.c */
|
||||
struct serverfd *allocate_sfd(union mysockaddr *addr, struct serverfd **sfds);
|
||||
int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp);
|
||||
int random_sock(int family);
|
||||
void pre_allocate_sfds(void);
|
||||
int reload_servers(char *fname);
|
||||
void check_servers(void);
|
||||
int enumerate_interfaces();
|
||||
@@ -675,8 +748,12 @@ struct in_addr get_ifaddr(char *intr);
|
||||
void dhcp_init(void);
|
||||
void dhcp_packet(time_t now);
|
||||
|
||||
struct dhcp_context *address_available(struct dhcp_context *context, struct in_addr addr);
|
||||
struct dhcp_context *narrow_context(struct dhcp_context *context, struct in_addr taddr);
|
||||
struct dhcp_context *address_available(struct dhcp_context *context,
|
||||
struct in_addr addr,
|
||||
struct dhcp_netid *netids);
|
||||
struct dhcp_context *narrow_context(struct dhcp_context *context,
|
||||
struct in_addr taddr,
|
||||
struct dhcp_netid *netids);
|
||||
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int negonly);
|
||||
int address_allocate(struct dhcp_context *context,
|
||||
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
|
||||
@@ -688,7 +765,7 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
|
||||
int hw_type, char *hostname);
|
||||
void dhcp_update_configs(struct dhcp_config *configs);
|
||||
void dhcp_read_ethers(void);
|
||||
void dhcp_read_hosts(void);
|
||||
void check_dhcp_hosts(int fatal);
|
||||
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr);
|
||||
char *strip_hostname(char *hostname);
|
||||
char *host_from_dns(struct in_addr addr);
|
||||
@@ -703,6 +780,7 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
||||
void lease_set_hostname(struct dhcp_lease *lease, char *name,
|
||||
char *suffix, int auth);
|
||||
void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now);
|
||||
void lease_set_interface(struct dhcp_lease *lease, int interface);
|
||||
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
|
||||
unsigned char *clid, int clid_len);
|
||||
struct dhcp_lease *lease_find_by_addr(struct in_addr addr);
|
||||
@@ -712,7 +790,7 @@ int do_script_run(time_t now);
|
||||
void rerun_scripts(void);
|
||||
|
||||
/* rfc2131.c */
|
||||
size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
size_t sz, time_t now, int unicast_dest, int *is_inform);
|
||||
|
||||
/* dnsmasq.c */
|
||||
@@ -729,18 +807,19 @@ void load_dhcp(time_t now);
|
||||
/* netlink.c */
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
void netlink_init(void);
|
||||
int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)());
|
||||
void netlink_multicast(void);
|
||||
#endif
|
||||
|
||||
/* bpf.c */
|
||||
#ifndef HAVE_LINUX_NETWORK
|
||||
#ifdef HAVE_BSD_NETWORK
|
||||
void init_bpf(void);
|
||||
void send_via_bpf(struct dhcp_packet *mess, size_t len,
|
||||
struct in_addr iface_addr, struct ifreq *ifr);
|
||||
int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)());
|
||||
#endif
|
||||
|
||||
/* bpf.c or netlink.c */
|
||||
int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)());
|
||||
|
||||
/* dbus.c */
|
||||
#ifdef HAVE_DBUS
|
||||
char *dbus_init(void);
|
||||
@@ -750,7 +829,7 @@ void set_dbus_listeners(int *maxfdp, fd_set *rset, fd_set *wset, fd_set *eset);
|
||||
|
||||
/* helper.c */
|
||||
#ifndef NO_FORK
|
||||
int create_helper(int log_fd, long max_fd);
|
||||
int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd);
|
||||
void helper_write(void);
|
||||
void queue_script(int action, struct dhcp_lease *lease,
|
||||
char *hostname, time_t now);
|
||||
|
||||
383
src/forward.c
383
src/forward.c
@@ -1,27 +1,30 @@
|
||||
/* dnsmasq is Copyright (c) 2000 - 2005 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991.
|
||||
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
static struct frec *frec_list = NULL;
|
||||
|
||||
static struct frec *lookup_frec(unsigned short id, unsigned int crc);
|
||||
static struct frec *lookup_frec_by_sender(unsigned short id,
|
||||
union mysockaddr *addr,
|
||||
unsigned int crc);
|
||||
static unsigned short get_id(int force, unsigned short force_id, unsigned int crc);
|
||||
static void free_frec(struct frec *f);
|
||||
static struct randfd *allocate_rfd(int family);
|
||||
|
||||
|
||||
/* Send a UDP packet with it's source address set as "source"
|
||||
/* Send a UDP packet with its source address set as "source"
|
||||
unless nowild is true, when we just send it with the kernel default */
|
||||
static void send_from(int fd, int nowild, char *packet, size_t len,
|
||||
union mysockaddr *to, struct all_addr *source,
|
||||
@@ -140,7 +143,7 @@ static unsigned short search_servers(time_t now, struct all_addr **addrpp,
|
||||
*addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
|
||||
#endif
|
||||
}
|
||||
else if (!flags)
|
||||
else if (!flags || (flags & F_NXDOMAIN))
|
||||
flags = F_NOERR;
|
||||
}
|
||||
}
|
||||
@@ -161,9 +164,9 @@ static unsigned short search_servers(time_t now, struct all_addr **addrpp,
|
||||
flags = F_NXDOMAIN;
|
||||
else if (serv->flags & SERV_LITERAL_ADDRESS)
|
||||
{
|
||||
if ((sflag | F_QUERY ) & qtype)
|
||||
if (sflag & qtype)
|
||||
{
|
||||
flags = qtype & ~F_BIGNAME;
|
||||
flags = sflag;
|
||||
if (serv->addr.sa.sa_family == AF_INET)
|
||||
*addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
|
||||
#ifdef HAVE_IPV6
|
||||
@@ -171,37 +174,36 @@ static unsigned short search_servers(time_t now, struct all_addr **addrpp,
|
||||
*addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
|
||||
#endif
|
||||
}
|
||||
else if (!flags)
|
||||
else if (!flags || (flags & F_NXDOMAIN))
|
||||
flags = F_NOERR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & ~(F_NOERR | F_NXDOMAIN)) /* flags set here means a literal found */
|
||||
{
|
||||
if (flags & F_QUERY)
|
||||
log_query(F_CONFIG | F_FORWARD | F_NEG, qdomain, NULL, 0, NULL, 0);
|
||||
else
|
||||
log_query(F_CONFIG | F_FORWARD | flags, qdomain, *addrpp, 0, NULL, 0);
|
||||
}
|
||||
else if (qtype && !(qtype & F_BIGNAME) &&
|
||||
(daemon->options & OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
|
||||
/* don't forward simple names, make exception from NS queries and empty name. */
|
||||
if (flags == 0 && !(qtype & F_BIGNAME) &&
|
||||
(daemon->options & OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
|
||||
/* don't forward simple names, make exception for NS queries and empty name. */
|
||||
flags = F_NXDOMAIN;
|
||||
|
||||
if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now))
|
||||
flags = F_NOERR;
|
||||
|
||||
if (flags == F_NXDOMAIN || flags == F_NOERR)
|
||||
log_query(F_CONFIG | F_FORWARD | F_NEG | qtype | (flags & F_NXDOMAIN), qdomain, NULL, 0, NULL, 0);
|
||||
if (flags)
|
||||
{
|
||||
int logflags = 0;
|
||||
|
||||
if (flags == F_NXDOMAIN || flags == F_NOERR)
|
||||
logflags = F_NEG | qtype;
|
||||
|
||||
log_query(logflags | flags | F_CONFIG | F_FORWARD, qdomain, *addrpp, NULL);
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
/* returns new last_server */
|
||||
static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
struct all_addr *dst_addr, unsigned int dst_iface,
|
||||
HEADER *header, size_t plen, time_t now, struct frec *forward)
|
||||
static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
struct all_addr *dst_addr, unsigned int dst_iface,
|
||||
HEADER *header, size_t plen, time_t now, struct frec *forward)
|
||||
{
|
||||
char *domain = NULL;
|
||||
int type = 0;
|
||||
@@ -218,6 +220,7 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
{
|
||||
/* retry on existing query, send to all available servers */
|
||||
domain = forward->sentto->domain;
|
||||
forward->sentto->failed_queries++;
|
||||
if (!(daemon->options & OPT_ORDER))
|
||||
{
|
||||
forward->forwardall = 1;
|
||||
@@ -286,7 +289,32 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
(type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
|
||||
!(start->flags & SERV_LITERAL_ADDRESS))
|
||||
{
|
||||
if (sendto(start->sfd->fd, (char *)header, plen, 0,
|
||||
int fd;
|
||||
|
||||
/* find server socket to use, may need to get random one. */
|
||||
if (start->sfd)
|
||||
fd = start->sfd->fd;
|
||||
else
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
if (start->addr.sa.sa_family == AF_INET6)
|
||||
{
|
||||
if (!forward->rfd6 &&
|
||||
!(forward->rfd6 = allocate_rfd(AF_INET6)))
|
||||
break;
|
||||
fd = forward->rfd6->fd;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (!forward->rfd4 &&
|
||||
!(forward->rfd4 = allocate_rfd(AF_INET)))
|
||||
break;
|
||||
fd = forward->rfd4->fd;
|
||||
}
|
||||
}
|
||||
|
||||
if (sendto(fd, (char *)header, plen, 0,
|
||||
&start->addr.sa,
|
||||
sa_len(&start->addr)) == -1)
|
||||
{
|
||||
@@ -303,14 +331,13 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
strcpy(daemon->namebuff, "query");
|
||||
if (start->addr.sa.sa_family == AF_INET)
|
||||
log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&start->addr.in.sin_addr, 0,
|
||||
NULL, 0);
|
||||
(struct all_addr *)&start->addr.in.sin_addr, NULL);
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&start->addr.in6.sin6_addr, 0,
|
||||
NULL, 0);
|
||||
(struct all_addr *)&start->addr.in6.sin6_addr, NULL);
|
||||
#endif
|
||||
start->queries++;
|
||||
forwarded = 1;
|
||||
forward->sentto = start;
|
||||
if (!forward->forwardall)
|
||||
@@ -327,11 +354,11 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
}
|
||||
|
||||
if (forwarded)
|
||||
return;
|
||||
return 1;
|
||||
|
||||
/* could not send on, prepare to return */
|
||||
header->id = htons(forward->orig_id);
|
||||
forward->sentto = NULL; /* cancel */
|
||||
free_frec(forward); /* cancel */
|
||||
}
|
||||
|
||||
/* could not send on, return empty answer or address if known for whole domain */
|
||||
@@ -341,7 +368,7 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
send_from(udpfd, daemon->options & OPT_NOWILD, (char *)header, plen, udpaddr, dst_addr, dst_iface);
|
||||
}
|
||||
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t process_reply(HEADER *header, time_t now,
|
||||
@@ -399,7 +426,11 @@ static size_t process_reply(HEADER *header, time_t now,
|
||||
header->rcode = NOERROR;
|
||||
}
|
||||
|
||||
extract_addresses(header, n, daemon->namebuff, now);
|
||||
if (extract_addresses(header, n, daemon->namebuff, now))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected"));
|
||||
munged = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* do this after extract_addresses. Ensure NODATA reply and remove
|
||||
@@ -419,7 +450,7 @@ static size_t process_reply(HEADER *header, time_t now,
|
||||
}
|
||||
|
||||
/* sets new last_server */
|
||||
void reply_query(struct serverfd *sfd, time_t now)
|
||||
void reply_query(int fd, int family, time_t now)
|
||||
{
|
||||
/* packet from peer server, extract data for cache, and send to
|
||||
original requester */
|
||||
@@ -427,90 +458,101 @@ void reply_query(struct serverfd *sfd, time_t now)
|
||||
union mysockaddr serveraddr;
|
||||
struct frec *forward;
|
||||
socklen_t addrlen = sizeof(serveraddr);
|
||||
ssize_t n = recvfrom(sfd->fd, daemon->packet, daemon->edns_pktsz, 0, &serveraddr.sa, &addrlen);
|
||||
ssize_t n = recvfrom(fd, daemon->packet, daemon->edns_pktsz, 0, &serveraddr.sa, &addrlen);
|
||||
size_t nn;
|
||||
|
||||
struct server *server;
|
||||
|
||||
/* packet buffer overwritten */
|
||||
daemon->srv_save = NULL;
|
||||
|
||||
/* 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;
|
||||
serveraddr.sa.sa_family = family;
|
||||
#ifdef HAVE_IPV6
|
||||
if (serveraddr.sa.sa_family == AF_INET6)
|
||||
serveraddr.in6.sin6_flowinfo = 0;
|
||||
#endif
|
||||
|
||||
/* spoof check: answer must come from known server, */
|
||||
for (server = daemon->servers; server; server = server->next)
|
||||
if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
|
||||
sockaddr_isequal(&server->addr, &serveraddr))
|
||||
break;
|
||||
|
||||
header = (HEADER *)daemon->packet;
|
||||
|
||||
if (n >= (int)sizeof(HEADER) && header->qr &&
|
||||
(forward = lookup_frec(ntohs(header->id), questions_crc(header, n, daemon->namebuff))))
|
||||
if (!server ||
|
||||
n < (int)sizeof(HEADER) || !header->qr ||
|
||||
!(forward = lookup_frec(ntohs(header->id), questions_crc(header, n, daemon->namebuff))))
|
||||
return;
|
||||
|
||||
server = forward->sentto;
|
||||
|
||||
if ((header->rcode == SERVFAIL || header->rcode == REFUSED) &&
|
||||
!(daemon->options & OPT_ORDER) &&
|
||||
forward->forwardall == 0)
|
||||
/* for broken servers, attempt to send to another one. */
|
||||
{
|
||||
struct server *server = forward->sentto;
|
||||
unsigned char *pheader;
|
||||
size_t plen;
|
||||
int is_sign;
|
||||
|
||||
if ((header->rcode == SERVFAIL || header->rcode == REFUSED) &&
|
||||
!(daemon->options & OPT_ORDER) &&
|
||||
forward->forwardall == 0)
|
||||
/* for broken servers, attempt to send to another one. */
|
||||
/* recreate query from reply */
|
||||
pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign);
|
||||
if (!is_sign)
|
||||
{
|
||||
unsigned char *pheader;
|
||||
size_t plen;
|
||||
int is_sign;
|
||||
header->ancount = htons(0);
|
||||
header->nscount = htons(0);
|
||||
header->arcount = htons(0);
|
||||
if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
|
||||
{
|
||||
header->qr = 0;
|
||||
header->tc = 0;
|
||||
forward_query(-1, NULL, NULL, 0, header, nn, now, forward);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((forward->sentto->flags & SERV_TYPE) == 0)
|
||||
{
|
||||
if (header->rcode == SERVFAIL || header->rcode == REFUSED)
|
||||
server = NULL;
|
||||
else
|
||||
{
|
||||
struct server *last_server;
|
||||
|
||||
/* recreate query from reply */
|
||||
pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign);
|
||||
if (!is_sign)
|
||||
{
|
||||
header->ancount = htons(0);
|
||||
header->nscount = htons(0);
|
||||
header->arcount = htons(0);
|
||||
if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
|
||||
{
|
||||
header->qr = 0;
|
||||
header->tc = 0;
|
||||
forward_query(-1, NULL, NULL, 0, header, nn, now, forward);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((forward->sentto->flags & SERV_TYPE) == 0)
|
||||
/* find good server by address if possible, otherwise assume the last one we sent to */
|
||||
for (last_server = daemon->servers; last_server; last_server = last_server->next)
|
||||
if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
|
||||
sockaddr_isequal(&last_server->addr, &serveraddr))
|
||||
{
|
||||
server = last_server;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!(daemon->options & OPT_ALL_SERVERS))
|
||||
daemon->last_server = server;
|
||||
}
|
||||
|
||||
/* If the answer is an error, keep the forward record in place in case
|
||||
we get a good reply from another server. Kill it when we've
|
||||
had replies from all to avoid filling the forwarding table when
|
||||
everything is broken */
|
||||
if (forward->forwardall == 0 || --forward->forwardall == 1 ||
|
||||
(header->rcode != REFUSED && header->rcode != SERVFAIL))
|
||||
{
|
||||
if ((nn = process_reply(header, now, server, (size_t)n)))
|
||||
{
|
||||
if (header->rcode == SERVFAIL || header->rcode == REFUSED)
|
||||
server = NULL;
|
||||
else
|
||||
{
|
||||
struct server *last_server;
|
||||
/* find good server by address if possible, otherwise assume the last one we sent to */
|
||||
for (last_server = daemon->servers; last_server; last_server = last_server->next)
|
||||
if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
|
||||
sockaddr_isequal(&last_server->addr, &serveraddr))
|
||||
{
|
||||
server = last_server;
|
||||
break;
|
||||
}
|
||||
}
|
||||
daemon->last_server = server;
|
||||
}
|
||||
|
||||
/* If the answer is an error, keep the forward record in place in case
|
||||
we get a good reply from another server. Kill it when we've
|
||||
had replies from all to avoid filling the forwarding table when
|
||||
everything is broken */
|
||||
if (forward->forwardall == 0 || --forward->forwardall == 1 ||
|
||||
(header->rcode != REFUSED && header->rcode != SERVFAIL))
|
||||
{
|
||||
if ((nn = process_reply(header, now, server, (size_t)n)))
|
||||
{
|
||||
header->id = htons(forward->orig_id);
|
||||
header->ra = 1; /* recursion if available */
|
||||
send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, nn,
|
||||
&forward->source, &forward->dest, forward->iface);
|
||||
}
|
||||
forward->sentto = NULL; /* cancel */
|
||||
header->id = htons(forward->orig_id);
|
||||
header->ra = 1; /* recursion if available */
|
||||
send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, nn,
|
||||
&forward->source, &forward->dest, forward->iface);
|
||||
}
|
||||
free_frec(forward); /* cancel */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void receive_query(struct listener *listen, time_t now)
|
||||
{
|
||||
HEADER *header = (HEADER *)daemon->packet;
|
||||
@@ -531,6 +573,9 @@ void receive_query(struct listener *listen, time_t now)
|
||||
#endif
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
|
||||
#elif defined(IP_RECVDSTADDR) && defined(HAVE_SOLARIS_NETWORK)
|
||||
char control[CMSG_SPACE(sizeof(struct in_addr)) +
|
||||
CMSG_SPACE(sizeof(unsigned int))];
|
||||
#elif defined(IP_RECVDSTADDR)
|
||||
char control[CMSG_SPACE(sizeof(struct in_addr)) +
|
||||
CMSG_SPACE(sizeof(struct sockaddr_dl))];
|
||||
@@ -598,7 +643,11 @@ void receive_query(struct listener *listen, time_t now)
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
|
||||
dst_addr_4 = dst_addr.addr.addr4 = *((struct in_addr *)CMSG_DATA(cmptr));
|
||||
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
|
||||
#ifdef HAVE_SOLARIS_NETWORK
|
||||
if_index = *((unsigned int *)CMSG_DATA(cmptr));
|
||||
#else
|
||||
if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -641,23 +690,33 @@ void receive_query(struct listener *listen, time_t now)
|
||||
|
||||
if (extract_request(header, (size_t)n, daemon->namebuff, &type))
|
||||
{
|
||||
char types[20];
|
||||
|
||||
querystr(types, type);
|
||||
|
||||
if (listen->family == AF_INET)
|
||||
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&source_addr.in.sin_addr, type, NULL, 0);
|
||||
(struct all_addr *)&source_addr.in.sin_addr, types);
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&source_addr.in6.sin6_addr, type, NULL, 0);
|
||||
(struct all_addr *)&source_addr.in6.sin6_addr, types);
|
||||
#endif
|
||||
}
|
||||
|
||||
m = answer_request (header, ((char *) header) + PACKETSZ, (size_t)n,
|
||||
dst_addr_4, netmask, now);
|
||||
if (m >= 1)
|
||||
send_from(listen->fd, daemon->options & OPT_NOWILD, (char *)header, m, &source_addr, &dst_addr, if_index);
|
||||
{
|
||||
send_from(listen->fd, daemon->options & OPT_NOWILD, (char *)header,
|
||||
m, &source_addr, &dst_addr, if_index);
|
||||
daemon->local_answer++;
|
||||
}
|
||||
else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
|
||||
header, (size_t)n, now, NULL))
|
||||
daemon->queries_forwarded++;
|
||||
else
|
||||
forward_query(listen->fd, &source_addr, &dst_addr, if_index,
|
||||
header, (size_t)n, now, NULL);
|
||||
daemon->local_answer++;
|
||||
}
|
||||
|
||||
/* The daemon forks before calling this: it should deal with one connection,
|
||||
@@ -696,13 +755,17 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
|
||||
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) != -1)
|
||||
{
|
||||
char types[20];
|
||||
|
||||
querystr(types, qtype);
|
||||
|
||||
if (peer_addr.sa.sa_family == AF_INET)
|
||||
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&peer_addr.in.sin_addr, qtype, NULL, 0);
|
||||
(struct all_addr *)&peer_addr.in.sin_addr, types);
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&peer_addr.in6.sin6_addr, qtype, NULL, 0);
|
||||
(struct all_addr *)&peer_addr.in6.sin6_addr, types);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -757,7 +820,8 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
|
||||
if ((last_server->tcpfd == -1) &&
|
||||
(last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) != -1 &&
|
||||
connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1)
|
||||
(!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) ||
|
||||
connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
|
||||
{
|
||||
close(last_server->tcpfd);
|
||||
last_server->tcpfd = -1;
|
||||
@@ -765,7 +829,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
|
||||
if (last_server->tcpfd == -1)
|
||||
continue;
|
||||
|
||||
|
||||
c1 = size >> 8;
|
||||
c2 = size;
|
||||
|
||||
@@ -779,7 +843,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
last_server->tcpfd = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
m = (c1 << 8) | c2;
|
||||
if (!read_write(last_server->tcpfd, packet, m, 1))
|
||||
return packet;
|
||||
@@ -788,11 +852,11 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
strcpy(daemon->namebuff, "query");
|
||||
if (last_server->addr.sa.sa_family == AF_INET)
|
||||
log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&last_server->addr.in.sin_addr, 0, NULL, 0);
|
||||
(struct all_addr *)&last_server->addr.in.sin_addr, NULL);
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&last_server->addr.in6.sin6_addr, 0, NULL, 0);
|
||||
(struct all_addr *)&last_server->addr.in6.sin6_addr, NULL);
|
||||
#endif
|
||||
|
||||
/* There's no point in updating the cache, since this process will exit and
|
||||
@@ -830,34 +894,99 @@ static struct frec *allocate_frec(time_t now)
|
||||
|
||||
if ((f = (struct frec *)whine_malloc(sizeof(struct frec))))
|
||||
{
|
||||
f->next = frec_list;
|
||||
f->next = daemon->frec_list;
|
||||
f->time = now;
|
||||
f->sentto = NULL;
|
||||
frec_list = f;
|
||||
f->rfd4 = NULL;
|
||||
#ifdef HAVE_IPV6
|
||||
f->rfd6 = NULL;
|
||||
#endif
|
||||
daemon->frec_list = f;
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
static struct randfd *allocate_rfd(int family)
|
||||
{
|
||||
static int finger = 0;
|
||||
int i;
|
||||
|
||||
/* limit the number of sockets we have open to avoid starvation of
|
||||
(eg) TFTP. Once we have a reasonable number, randomness should be OK */
|
||||
|
||||
for (i = 0; i < RANDOM_SOCKS; i++)
|
||||
if (daemon->randomsocks[i].refcount == 0 &&
|
||||
(daemon->randomsocks[i].fd = random_sock(family)) != -1)
|
||||
{
|
||||
daemon->randomsocks[i].refcount = 1;
|
||||
daemon->randomsocks[i].family = family;
|
||||
return &daemon->randomsocks[i];
|
||||
}
|
||||
|
||||
/* No free ones, grab an existing one */
|
||||
for (i = 0; i < RANDOM_SOCKS; i++)
|
||||
{
|
||||
int j = (i+finger) % RANDOM_SOCKS;
|
||||
if (daemon->randomsocks[j].family == family && daemon->randomsocks[j].refcount != 0xffff)
|
||||
{
|
||||
finger = j;
|
||||
daemon->randomsocks[j].refcount++;
|
||||
return &daemon->randomsocks[j];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL; /* doom */
|
||||
}
|
||||
|
||||
static void free_frec(struct frec *f)
|
||||
{
|
||||
if (f->rfd4 && --(f->rfd4->refcount) == 0)
|
||||
close(f->rfd4->fd);
|
||||
|
||||
f->rfd4 = NULL;
|
||||
f->sentto = NULL;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (f->rfd6 && --(f->rfd6->refcount) == 0)
|
||||
close(f->rfd6->fd);
|
||||
|
||||
f->rfd6 = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* if wait==NULL return a free or older than TIMEOUT record.
|
||||
else return *wait zero if one available, or *wait is delay to
|
||||
when the oldest in-use record will expire. */
|
||||
when the oldest in-use record will expire. Impose an absolute
|
||||
limit of 4*TIMEOUT before we wipe things (for random sockets) */
|
||||
struct frec *get_new_frec(time_t now, int *wait)
|
||||
{
|
||||
struct frec *f, *oldest;
|
||||
struct frec *f, *oldest, *target;
|
||||
int count;
|
||||
|
||||
if (wait)
|
||||
*wait = 0;
|
||||
|
||||
for (f = frec_list, oldest = NULL, count = 0; f; f = f->next, count++)
|
||||
for (f = daemon->frec_list, oldest = NULL, target = NULL, count = 0; f; f = f->next, count++)
|
||||
if (!f->sentto)
|
||||
target = f;
|
||||
else
|
||||
{
|
||||
f->time = now;
|
||||
return f;
|
||||
if (difftime(now, f->time) >= 4*TIMEOUT)
|
||||
{
|
||||
free_frec(f);
|
||||
target = f;
|
||||
}
|
||||
|
||||
if (!oldest || difftime(f->time, oldest->time) <= 0)
|
||||
oldest = f;
|
||||
}
|
||||
else if (!oldest || difftime(f->time, oldest->time) <= 0)
|
||||
oldest = f;
|
||||
|
||||
if (target)
|
||||
{
|
||||
target->time = now;
|
||||
return target;
|
||||
}
|
||||
|
||||
/* can't find empty one, use oldest if there is one
|
||||
and it's older than timeout */
|
||||
@@ -872,7 +1001,7 @@ struct frec *get_new_frec(time_t now, int *wait)
|
||||
|
||||
if (!wait)
|
||||
{
|
||||
oldest->sentto = 0;
|
||||
free_frec(oldest);
|
||||
oldest->time = now;
|
||||
}
|
||||
return oldest;
|
||||
@@ -898,7 +1027,7 @@ static struct frec *lookup_frec(unsigned short id, unsigned int crc)
|
||||
{
|
||||
struct frec *f;
|
||||
|
||||
for(f = frec_list; f; f = f->next)
|
||||
for(f = daemon->frec_list; f; f = f->next)
|
||||
if (f->sentto && f->new_id == id &&
|
||||
(f->crc == crc || crc == 0xffffffff))
|
||||
return f;
|
||||
@@ -912,7 +1041,7 @@ static struct frec *lookup_frec_by_sender(unsigned short id,
|
||||
{
|
||||
struct frec *f;
|
||||
|
||||
for(f = frec_list; f; f = f->next)
|
||||
for(f = daemon->frec_list; f; f = f->next)
|
||||
if (f->sentto &&
|
||||
f->orig_id == id &&
|
||||
f->crc == crc &&
|
||||
@@ -927,9 +1056,9 @@ void server_gone(struct server *server)
|
||||
{
|
||||
struct frec *f;
|
||||
|
||||
for (f = frec_list; f; f = f->next)
|
||||
for (f = daemon->frec_list; f; f = f->next)
|
||||
if (f->sentto && f->sentto == server)
|
||||
f->sentto = NULL;
|
||||
free_frec(f);
|
||||
|
||||
if (daemon->last_server == server)
|
||||
daemon->last_server = NULL;
|
||||
@@ -950,7 +1079,7 @@ static unsigned short get_id(int force, unsigned short force_id, unsigned int cr
|
||||
{
|
||||
struct frec *f = lookup_frec(force_id, crc);
|
||||
if (f)
|
||||
f->sentto = NULL; /* free */
|
||||
free_frec(f); /* free */
|
||||
ret = force_id;
|
||||
}
|
||||
else do
|
||||
|
||||
130
src/helper.c
130
src/helper.c
@@ -1,13 +1,17 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2006 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991.
|
||||
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
@@ -26,6 +30,8 @@
|
||||
|
||||
#ifndef NO_FORK
|
||||
|
||||
static void my_setenv(const char *name, const char *value, int *error);
|
||||
|
||||
struct script_data
|
||||
{
|
||||
unsigned char action, hwaddr_len, hwaddr_type;
|
||||
@@ -38,27 +44,24 @@ struct script_data
|
||||
time_t expires;
|
||||
#endif
|
||||
unsigned char hwaddr[DHCP_CHADDR_MAX];
|
||||
char interface[IF_NAMESIZE];
|
||||
};
|
||||
|
||||
static struct script_data *buf = NULL;
|
||||
static size_t bytes_in_buf = 0, buf_size = 0;
|
||||
|
||||
int create_helper(int event_fd, long max_fd)
|
||||
int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
{
|
||||
pid_t pid;
|
||||
int i, pipefd[2];
|
||||
struct sigaction sigact;
|
||||
|
||||
if (!daemon->dhcp || !daemon->lease_change_command)
|
||||
return -1;
|
||||
|
||||
/* create the pipe through which the main program sends us commands,
|
||||
then fork our process. By now it's too late to die(), we just log
|
||||
any failure via the main process. */
|
||||
then fork our process. */
|
||||
if (pipe(pipefd) == -1 || !fix_fd(pipefd[1]) || (pid = fork()) == -1)
|
||||
{
|
||||
send_event(event_fd, EVENT_PIPE_ERR, errno);
|
||||
return -1;
|
||||
send_event(err_fd, EVENT_PIPE_ERR, errno);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
if (pid != 0)
|
||||
@@ -75,7 +78,29 @@ int create_helper(int event_fd, long max_fd)
|
||||
sigaction(SIGTERM, &sigact, NULL);
|
||||
sigaction(SIGALRM, &sigact, NULL);
|
||||
|
||||
/* close all the sockets etc, we don't need them here */
|
||||
if (!(daemon->options & OPT_DEBUG) && uid != 0)
|
||||
{
|
||||
gid_t dummy;
|
||||
if (setgroups(0, &dummy) == -1 ||
|
||||
setgid(gid) == -1 ||
|
||||
setuid(uid) == -1)
|
||||
{
|
||||
if (daemon->options & OPT_NO_FORK)
|
||||
/* send error to daemon process if no-fork */
|
||||
send_event(event_fd, EVENT_HUSER_ERR, errno);
|
||||
else
|
||||
{
|
||||
/* kill daemon */
|
||||
send_event(event_fd, EVENT_DIE, 0);
|
||||
/* return error */
|
||||
send_event(err_fd, EVENT_HUSER_ERR, errno);;
|
||||
}
|
||||
_exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* close all the sockets etc, we don't need them here. This closes err_fd, so that
|
||||
main process can return. */
|
||||
for (max_fd--; max_fd > 0; max_fd--)
|
||||
if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO &&
|
||||
max_fd != STDIN_FILENO && max_fd != pipefd[0] && max_fd != event_fd)
|
||||
@@ -87,6 +112,7 @@ int create_helper(int event_fd, long max_fd)
|
||||
struct script_data data;
|
||||
char *p, *action_str, *hostname = NULL;
|
||||
unsigned char *buf = (unsigned char *)daemon->namebuff;
|
||||
int err = 0;
|
||||
|
||||
/* we read zero bytes when pipe closed: this is our signal to exit */
|
||||
if (!read_write(pipefd[0], (unsigned char *)&data, sizeof(data), 1))
|
||||
@@ -166,16 +192,15 @@ int create_helper(int event_fd, long max_fd)
|
||||
}
|
||||
|
||||
if (data.clid_len != 0)
|
||||
setenv("DNSMASQ_CLIENT_ID", daemon->packet, 1);
|
||||
else
|
||||
unsetenv("DNSMASQ_CLIENT_ID");
|
||||
|
||||
my_setenv("DNSMASQ_CLIENT_ID", daemon->packet, &err);
|
||||
|
||||
if (strlen(data.interface) != 0)
|
||||
my_setenv("DNSMASQ_INTERFACE", data.interface, &err);
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, 1);
|
||||
unsetenv("DNSMASQ_LEASE_EXPIRES");
|
||||
my_setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, &err);
|
||||
#else
|
||||
setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, 1);
|
||||
unsetenv("DNSMASQ_LEASE_LENGTH");
|
||||
my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
|
||||
#endif
|
||||
|
||||
if (data.vclass_len != 0)
|
||||
@@ -184,11 +209,9 @@ int create_helper(int event_fd, long max_fd)
|
||||
/* cannot have = chars in env - truncate if found . */
|
||||
if ((p = strchr((char *)buf, '=')))
|
||||
*p = 0;
|
||||
setenv("DNSMASQ_VENDOR_CLASS", (char *)buf, 1);
|
||||
my_setenv("DNSMASQ_VENDOR_CLASS", (char *)buf, &err);
|
||||
buf += data.vclass_len;
|
||||
}
|
||||
else
|
||||
unsetenv("DNSMASQ_VENDOR_CLASS");
|
||||
|
||||
if (data.uclass_len != 0)
|
||||
{
|
||||
@@ -203,14 +226,14 @@ int create_helper(int event_fd, long max_fd)
|
||||
if (strlen((char *)buf) != 0)
|
||||
{
|
||||
sprintf(daemon->dhcp_buff2, "DNSMASQ_USER_CLASS%i", i++);
|
||||
setenv(daemon->dhcp_buff2, (char *)buf, 1);
|
||||
my_setenv(daemon->dhcp_buff2, (char *)buf, &err);
|
||||
}
|
||||
buf += len;
|
||||
}
|
||||
}
|
||||
|
||||
sprintf(daemon->dhcp_buff2, "%u ", data.remaining_time);
|
||||
setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, 1);
|
||||
my_setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, &err);
|
||||
|
||||
if (data.hostname_len != 0)
|
||||
{
|
||||
@@ -222,11 +245,9 @@ int create_helper(int event_fd, long max_fd)
|
||||
|
||||
if (data.action == ACTION_OLD_HOSTNAME && hostname)
|
||||
{
|
||||
setenv("DNSMASQ_OLD_HOSTNAME", hostname, 1);
|
||||
my_setenv("DNSMASQ_OLD_HOSTNAME", hostname, &err);
|
||||
hostname = NULL;
|
||||
}
|
||||
else
|
||||
unsetenv("DNSMASQ_OLD_HOSTNAME");
|
||||
|
||||
/* we need to have the event_fd around if exec fails */
|
||||
if ((i = fcntl(event_fd, F_GETFD)) != -1)
|
||||
@@ -234,16 +255,45 @@ int create_helper(int event_fd, long max_fd)
|
||||
close(pipefd[0]);
|
||||
|
||||
p = strrchr(daemon->lease_change_command, '/');
|
||||
execl(daemon->lease_change_command,
|
||||
p ? p+1 : daemon->lease_change_command,
|
||||
action_str, daemon->dhcp_buff, inet_ntoa(data.addr), hostname, (char*)NULL);
|
||||
|
||||
if (err == 0)
|
||||
{
|
||||
execl(daemon->lease_change_command,
|
||||
p ? p+1 : daemon->lease_change_command,
|
||||
action_str, daemon->dhcp_buff, inet_ntoa(data.addr), hostname, (char*)NULL);
|
||||
err = errno;
|
||||
}
|
||||
/* failed, send event so the main process logs the problem */
|
||||
send_event(event_fd, EVENT_EXEC_ERR, errno);
|
||||
send_event(event_fd, EVENT_EXEC_ERR, err);
|
||||
_exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void my_setenv(const char *name, const char *value, int *error)
|
||||
{
|
||||
if (*error == 0)
|
||||
{
|
||||
#if defined(HAVE_SOLARIS_NETWORK) && !defined(HAVE_SOLARIS_PRIVS)
|
||||
/* old Solaris is missing setenv..... */
|
||||
char *p;
|
||||
|
||||
if (!(p = malloc(strlen(name) + strlen(value) + 2)))
|
||||
*error = ENOMEM;
|
||||
else
|
||||
{
|
||||
strcpy(p, name);
|
||||
strcat(p, "=");
|
||||
strcat(p, value);
|
||||
|
||||
if (putenv(p) != 0)
|
||||
*error = errno;
|
||||
}
|
||||
#else
|
||||
if (setenv(name, value, 1) != 0)
|
||||
*error = errno;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* pack up lease data into a buffer */
|
||||
void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now)
|
||||
{
|
||||
@@ -291,6 +341,20 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
|
||||
buf->hostname_len = hostname_len;
|
||||
buf->addr = lease->addr;
|
||||
memcpy(buf->hwaddr, lease->hwaddr, lease->hwaddr_len);
|
||||
buf->interface[0] = 0;
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
if (lease->last_interface != 0)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
ifr.ifr_ifindex = lease->last_interface;
|
||||
if (ioctl(daemon->dhcpfd, SIOCGIFNAME, &ifr) != -1)
|
||||
strncpy(buf->interface, ifr.ifr_name, IF_NAMESIZE);
|
||||
}
|
||||
#else
|
||||
if (lease->last_interface != 0)
|
||||
if_indextoname(lease->last_interface, buf->interface);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
buf->length = lease->length;
|
||||
#else
|
||||
|
||||
10
src/isc.c
10
src/isc.c
@@ -1,13 +1,17 @@
|
||||
/* dnsmasq is Copyright (c) 2000 - 2005 by Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991.
|
||||
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
21
src/lease.c
21
src/lease.c
@@ -1,13 +1,17 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2006 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991.
|
||||
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
@@ -244,7 +248,7 @@ void lease_update_dns(void)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
if (dns_dirty)
|
||||
if (daemon->port != 0 && dns_dirty)
|
||||
{
|
||||
cache_unhash_dhcp();
|
||||
|
||||
@@ -476,6 +480,15 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix, int
|
||||
lease->changed = 1; /* run script on change */
|
||||
}
|
||||
|
||||
void lease_set_interface(struct dhcp_lease *lease, int interface)
|
||||
{
|
||||
if (lease->last_interface == interface)
|
||||
return;
|
||||
|
||||
lease->last_interface = interface;
|
||||
lease->changed = 1;
|
||||
}
|
||||
|
||||
void rerun_scripts(void)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
84
src/log.c
84
src/log.c
@@ -2,12 +2,16 @@
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991.
|
||||
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
@@ -46,8 +50,10 @@ static struct log_entry *entries = NULL;
|
||||
static struct log_entry *free_entries = NULL;
|
||||
|
||||
|
||||
void log_start(struct passwd *ent_pw)
|
||||
int log_start(struct passwd *ent_pw, int errfd)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
log_stderr = !!(daemon->options & OPT_DEBUG);
|
||||
|
||||
if (daemon->log_fac != -1)
|
||||
@@ -66,15 +72,11 @@ void log_start(struct passwd *ent_pw)
|
||||
max_logs = daemon->max_logs;
|
||||
|
||||
if (!log_reopen(daemon->log_file))
|
||||
die(_("cannot open %s: %s"), daemon->log_file ? daemon->log_file : "log", EC_FILE);
|
||||
|
||||
/* If we're running as root and going to change uid later,
|
||||
change the ownership here so that the file is always owned by
|
||||
the dnsmasq user. Then logrotate can just copy the owner.
|
||||
Failure of the chown call is OK, (for instance when started as non-root) */
|
||||
if (log_to_file && ent_pw && ent_pw->pw_uid != 0)
|
||||
fchown(log_fd, ent_pw->pw_uid, -1);
|
||||
|
||||
{
|
||||
send_event(errfd, EVENT_LOG_ERR, errno);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
/* if queuing is inhibited, make sure we allocate
|
||||
the one required buffer now. */
|
||||
if (max_logs == 0)
|
||||
@@ -83,29 +85,50 @@ void log_start(struct passwd *ent_pw)
|
||||
free_entries->next = NULL;
|
||||
entries_alloced = 1;
|
||||
}
|
||||
|
||||
/* If we're running as root and going to change uid later,
|
||||
change the ownership here so that the file is always owned by
|
||||
the dnsmasq user. Then logrotate can just copy the owner.
|
||||
Failure of the chown call is OK, (for instance when started as non-root) */
|
||||
if (log_to_file && ent_pw && ent_pw->pw_uid != 0 &&
|
||||
fchown(log_fd, ent_pw->pw_uid, -1) != 0)
|
||||
ret = errno;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int log_reopen(char *log_file)
|
||||
{
|
||||
int flags;
|
||||
|
||||
if (log_fd != -1)
|
||||
close(log_fd);
|
||||
|
||||
/* NOTE: umask is set to 022 by the time this gets called */
|
||||
|
||||
if (log_file)
|
||||
log_fd = open(log_file, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP);
|
||||
{
|
||||
log_fd = open(log_file, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP);
|
||||
return log_fd != -1;
|
||||
}
|
||||
else
|
||||
log_fd = socket(AF_UNIX, connection_type, 0);
|
||||
|
||||
if (log_fd == -1)
|
||||
return 0;
|
||||
|
||||
/* if max_logs is zero, leave the socket blocking */
|
||||
if (max_logs != 0 && (flags = fcntl(log_fd, F_GETFL)) != -1)
|
||||
fcntl(log_fd, F_SETFL, flags | O_NONBLOCK);
|
||||
#ifdef HAVE_SOLARIS_NETWORK
|
||||
/* Solaris logging is "different", /dev/log is not unix-domain socket.
|
||||
Just leave log_fd == -1 and use the vsyslog call for everything.... */
|
||||
# define _PATH_LOG "" /* dummy */
|
||||
log_fd = -1;
|
||||
#else
|
||||
{
|
||||
int flags;
|
||||
log_fd = socket(AF_UNIX, connection_type, 0);
|
||||
|
||||
if (log_fd == -1)
|
||||
return 0;
|
||||
|
||||
/* if max_logs is zero, leave the socket blocking */
|
||||
if (max_logs != 0 && (flags = fcntl(log_fd, F_GETFL)) != -1)
|
||||
fcntl(log_fd, F_SETFL, flags | O_NONBLOCK);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -187,7 +210,7 @@ static void log_write(void)
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
logaddr.sun_len = sizeof(logaddr) - sizeof(logaddr.sun_path) + strlen(_PATH_LOG) + 1;
|
||||
#endif
|
||||
logaddr.sun_family = AF_LOCAL;
|
||||
logaddr.sun_family = AF_UNIX;
|
||||
strncpy(logaddr.sun_path, _PATH_LOG, sizeof(logaddr.sun_path));
|
||||
|
||||
/* Got connection back? try again. */
|
||||
@@ -234,15 +257,15 @@ void my_syslog(int priority, const char *format, ...)
|
||||
size_t len;
|
||||
pid_t pid = getpid();
|
||||
|
||||
va_start(ap, format);
|
||||
|
||||
if (log_stderr)
|
||||
{
|
||||
fprintf(stderr, "dnsmasq: ");
|
||||
va_start(ap, format);
|
||||
vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
|
||||
|
||||
if (log_fd == -1)
|
||||
{
|
||||
/* fall-back to syslog if we die during startup or fail during running. */
|
||||
@@ -252,6 +275,7 @@ void my_syslog(int priority, const char *format, ...)
|
||||
openlog("dnsmasq", LOG_PID, log_fac);
|
||||
isopen = 1;
|
||||
}
|
||||
va_start(ap, format);
|
||||
vsyslog(priority, format, ap);
|
||||
va_end(ap);
|
||||
return;
|
||||
@@ -282,9 +306,11 @@ void my_syslog(int priority, const char *format, ...)
|
||||
if (!log_to_file)
|
||||
p += sprintf(p, "<%d>", priority | log_fac);
|
||||
|
||||
p += sprintf(p, "%.15s dnsmasq[%d]: ", ctime(&time_now) + 4, pid);
|
||||
p += sprintf(p, "%.15s dnsmasq[%d]: ", ctime(&time_now) + 4, (int)pid);
|
||||
len = p - entry->payload;
|
||||
va_start(ap, format);
|
||||
len += vsnprintf(p, MAX_MESSAGE - len, format, ap) + 1; /* include zero-terminator */
|
||||
va_end(ap);
|
||||
entry->length = len > MAX_MESSAGE ? MAX_MESSAGE : len;
|
||||
entry->offset = 0;
|
||||
entry->pid = pid;
|
||||
@@ -331,8 +357,6 @@ void my_syslog(int priority, const char *format, ...)
|
||||
log_write();
|
||||
}
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void set_log_writer(fd_set *set, int *maxfdp)
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2006 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991.
|
||||
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
309
src/network.c
309
src/network.c
@@ -1,13 +1,17 @@
|
||||
/* dnsmasq is Copyright (c) 2000 - 2006 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991.
|
||||
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
@@ -23,8 +27,8 @@ int iface_check(int family, struct all_addr *addr,
|
||||
|
||||
if (indexp)
|
||||
{
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
/* One form of bridging on FreeBSD has the property that packets
|
||||
#ifdef HAVE_BSD_BRIDGE
|
||||
/* One form of bridging on BSD has the property that packets
|
||||
can be recieved on bridge interfaces which do not have an IP address.
|
||||
We allow these to be treated as aliases of another interface which does have
|
||||
an IP address with --dhcp-bridge=interface,alias,alias */
|
||||
@@ -293,7 +297,7 @@ struct listener *create_wildcard_listeners(void)
|
||||
union mysockaddr addr;
|
||||
int opt = 1;
|
||||
struct listener *l, *l6 = NULL;
|
||||
int tcpfd, fd, tftpfd = -1;
|
||||
int tcpfd = -1, fd = -1, tftpfd = -1;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.in.sin_family = AF_INET;
|
||||
@@ -303,28 +307,32 @@ struct listener *create_wildcard_listeners(void)
|
||||
addr.in.sin_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1 ||
|
||||
(tcpfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
|
||||
return NULL;
|
||||
|
||||
if (setsockopt(tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
bind(tcpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1 ||
|
||||
listen(tcpfd, 5) == -1 ||
|
||||
!fix_fd(tcpfd) ||
|
||||
if (daemon->port != 0)
|
||||
{
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1 ||
|
||||
(tcpfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
|
||||
return NULL;
|
||||
|
||||
if (setsockopt(tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
bind(tcpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1 ||
|
||||
listen(tcpfd, 5) == -1 ||
|
||||
!fix_fd(tcpfd) ||
|
||||
#ifdef HAVE_IPV6
|
||||
!create_ipv6_listener(&l6, daemon->port) ||
|
||||
!create_ipv6_listener(&l6, daemon->port) ||
|
||||
#endif
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
!fix_fd(fd) ||
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
!fix_fd(fd) ||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1 ||
|
||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||
setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1 ||
|
||||
#endif
|
||||
bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
|
||||
return NULL;
|
||||
|
||||
bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
if (daemon->options & OPT_TFTP)
|
||||
{
|
||||
@@ -367,49 +375,52 @@ struct listener *create_bound_listeners(void)
|
||||
new->iface = iface;
|
||||
new->next = listeners;
|
||||
new->tftpfd = -1;
|
||||
new->tcpfd = -1;
|
||||
new->fd = -1;
|
||||
|
||||
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 ||
|
||||
!fix_fd(new->tcpfd) ||
|
||||
!fix_fd(new->fd))
|
||||
die(_("failed to create listening socket: %s"), NULL, EC_BADNET);
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (iface->addr.sa.sa_family == AF_INET6)
|
||||
{
|
||||
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, EC_BADNET);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bind(new->tcpfd, &iface->addr.sa, sa_len(&iface->addr)) == -1 ||
|
||||
bind(new->fd, &iface->addr.sa, sa_len(&iface->addr)) == -1)
|
||||
if (daemon->port != 0)
|
||||
{
|
||||
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 ||
|
||||
!fix_fd(new->tcpfd) ||
|
||||
!fix_fd(new->fd))
|
||||
die(_("failed to create listening socket: %s"), NULL, EC_BADNET);
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (iface->addr.sa.sa_family == AF_INET6 && errno == ENODEV)
|
||||
if (iface->addr.sa.sa_family == AF_INET6)
|
||||
{
|
||||
close(new->tcpfd);
|
||||
close(new->fd);
|
||||
free(new);
|
||||
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, EC_BADNET);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
if (bind(new->tcpfd, &iface->addr.sa, sa_len(&iface->addr)) == -1 ||
|
||||
bind(new->fd, &iface->addr.sa, sa_len(&iface->addr)) == -1)
|
||||
{
|
||||
prettyprint_addr(&iface->addr, daemon->namebuff);
|
||||
die(_("failed to bind listening socket for %s: %s"),
|
||||
daemon->namebuff, EC_BADNET);
|
||||
#ifdef HAVE_IPV6
|
||||
if (iface->addr.sa.sa_family == AF_INET6 && (errno == ENODEV || errno == EADDRNOTAVAIL))
|
||||
{
|
||||
close(new->tcpfd);
|
||||
close(new->fd);
|
||||
free(new);
|
||||
new = NULL;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
prettyprint_addr(&iface->addr, daemon->namebuff);
|
||||
die(_("failed to bind listening socket for %s: %s"),
|
||||
daemon->namebuff, EC_BADNET);
|
||||
}
|
||||
}
|
||||
else if (listen(new->tcpfd, 5) == -1)
|
||||
die(_("failed to listen on socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
else
|
||||
{
|
||||
listeners = new;
|
||||
if (listen(new->tcpfd, 5) == -1)
|
||||
die(_("failed to listen on socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
if ((daemon->options & OPT_TFTP) && iface->addr.sa.sa_family == AF_INET && iface->dhcp_ok)
|
||||
{
|
||||
short save = iface->addr.in.sin_port;
|
||||
@@ -421,18 +432,125 @@ struct listener *create_bound_listeners(void)
|
||||
die(_("failed to create TFTP socket: %s"), NULL, EC_BADNET);
|
||||
iface->addr.in.sin_port = save;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (new)
|
||||
listeners = new;
|
||||
}
|
||||
|
||||
return listeners;
|
||||
}
|
||||
|
||||
struct serverfd *allocate_sfd(union mysockaddr *addr, struct serverfd **sfds)
|
||||
|
||||
/* return a UDP socket bound to a random port, have to coper with straying into
|
||||
occupied port nos and reserved ones. */
|
||||
int random_sock(int family)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if ((fd = socket(family, SOCK_DGRAM, 0)) != -1)
|
||||
{
|
||||
union mysockaddr addr;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.in.sin_family = family;
|
||||
|
||||
if (fix_fd(fd))
|
||||
while (1)
|
||||
{
|
||||
unsigned short port = rand16();
|
||||
|
||||
if (port <= (unsigned short) daemon->min_port)
|
||||
continue;
|
||||
|
||||
if (family == AF_INET)
|
||||
{
|
||||
addr.in.sin_addr.s_addr = INADDR_ANY;
|
||||
addr.in.sin_port = htons(port);
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in.sin_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
addr.in6.sin6_addr = in6addr_any;
|
||||
addr.in6.sin6_port = htons(port);
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in6.sin6_len = sizeof(struct sockaddr_in6);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == 0)
|
||||
return fd;
|
||||
|
||||
if (errno != EADDRINUSE && errno != EACCES)
|
||||
break;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp)
|
||||
{
|
||||
union mysockaddr addr_copy = *addr;
|
||||
|
||||
/* cannot set source _port_ for TCP connections. */
|
||||
if (is_tcp)
|
||||
{
|
||||
if (addr_copy.sa.sa_family == AF_INET)
|
||||
addr_copy.in.sin_port = 0;
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
addr_copy.in6.sin6_port = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (bind(fd, (struct sockaddr *)&addr_copy, sa_len(&addr_copy)) == -1)
|
||||
return 0;
|
||||
|
||||
#if defined(SO_BINDTODEVICE)
|
||||
if (strlen(intname) != 0 &&
|
||||
setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intname, sizeof(intname)) == -1)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
|
||||
{
|
||||
struct serverfd *sfd;
|
||||
int errsave;
|
||||
|
||||
/* when using random ports, servers which would otherwise use
|
||||
the INADDR_ANY/port0 socket have sfd set to NULL */
|
||||
if (!daemon->osport)
|
||||
{
|
||||
errno = 0;
|
||||
|
||||
if (addr->sa.sa_family == AF_INET &&
|
||||
addr->in.sin_addr.s_addr == INADDR_ANY &&
|
||||
addr->in.sin_port == htons(0))
|
||||
return NULL;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (addr->sa.sa_family == AF_INET6 &&
|
||||
memcmp(&addr->in6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0 &&
|
||||
addr->in6.sin6_port == htons(0))
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* may have a suitable one already */
|
||||
for (sfd = *sfds; sfd; sfd = sfd->next )
|
||||
if (sockaddr_isequal(&sfd->source_addr, addr))
|
||||
for (sfd = daemon->sfds; sfd; sfd = sfd->next )
|
||||
if (sockaddr_isequal(&sfd->source_addr, addr) &&
|
||||
strcmp(intname, sfd->interface) == 0)
|
||||
return sfd;
|
||||
|
||||
/* need to make a new one. */
|
||||
@@ -446,23 +564,69 @@ struct serverfd *allocate_sfd(union mysockaddr *addr, struct serverfd **sfds)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bind(sfd->fd, (struct sockaddr *)addr, sa_len(addr)) == -1 ||
|
||||
!fix_fd(sfd->fd))
|
||||
{
|
||||
int errsave = errno; /* save error from bind. */
|
||||
if (!local_bind(sfd->fd, addr, intname, 0) || !fix_fd(sfd->fd))
|
||||
{
|
||||
errsave = errno; /* save error from bind. */
|
||||
close(sfd->fd);
|
||||
free(sfd);
|
||||
errno = errsave;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
strcpy(sfd->interface, intname);
|
||||
sfd->source_addr = *addr;
|
||||
sfd->next = *sfds;
|
||||
*sfds = sfd;
|
||||
|
||||
return sfd;
|
||||
sfd->next = daemon->sfds;
|
||||
daemon->sfds = sfd;
|
||||
return sfd;
|
||||
}
|
||||
|
||||
/* create upstream sockets during startup, before root is dropped which may be needed
|
||||
this allows query_port to be a low port and interface binding */
|
||||
void pre_allocate_sfds(void)
|
||||
{
|
||||
struct server *srv;
|
||||
|
||||
if (daemon->query_port != 0)
|
||||
{
|
||||
union mysockaddr addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.in.sin_family = AF_INET;
|
||||
addr.in.sin_addr.s_addr = INADDR_ANY;
|
||||
addr.in.sin_port = htons(daemon->query_port);
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in.sin_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
allocate_sfd(&addr, "");
|
||||
#ifdef HAVE_IPV6
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.in6.sin6_family = AF_INET6;
|
||||
addr.in6.sin6_addr = in6addr_any;
|
||||
addr.in6.sin6_port = htons(daemon->query_port);
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in6.sin6_len = sizeof(struct sockaddr_in6);
|
||||
#endif
|
||||
allocate_sfd(&addr, "");
|
||||
#endif
|
||||
}
|
||||
|
||||
for (srv = daemon->servers; srv; srv = srv->next)
|
||||
if (!(srv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
|
||||
!allocate_sfd(&srv->source_addr, srv->interface) &&
|
||||
errno != 0 &&
|
||||
(daemon->options & OPT_NOWILD))
|
||||
{
|
||||
prettyprint_addr(&srv->addr, daemon->namebuff);
|
||||
if (strlen(srv->interface) != 0)
|
||||
{
|
||||
strcat(daemon->namebuff, " ");
|
||||
strcat(daemon->namebuff, srv->interface);
|
||||
}
|
||||
die(_("failed to bind server socket for %s: %s"),
|
||||
daemon->namebuff, EC_BADNET);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void check_servers(void)
|
||||
{
|
||||
struct irec *iface;
|
||||
@@ -496,7 +660,9 @@ void check_servers(void)
|
||||
}
|
||||
|
||||
/* Do we need a socket set? */
|
||||
if (!new->sfd && !(new->sfd = allocate_sfd(&new->source_addr, &daemon->sfds)))
|
||||
if (!new->sfd &&
|
||||
!(new->sfd = allocate_sfd(&new->source_addr, new->interface)) &&
|
||||
errno != 0)
|
||||
{
|
||||
my_syslog(LOG_WARNING,
|
||||
_("ignoring nameserver %s - cannot make/bind socket: %s"),
|
||||
@@ -525,6 +691,8 @@ void check_servers(void)
|
||||
else if (!(new->flags & SERV_LITERAL_ADDRESS))
|
||||
my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s"), daemon->namebuff, port, s1, s2);
|
||||
}
|
||||
else if (strlen(new->interface) != 0)
|
||||
my_syslog(LOG_INFO, _("using nameserver %s#%d(via %s)"), daemon->namebuff, port, new->interface);
|
||||
else
|
||||
my_syslog(LOG_INFO, _("using nameserver %s#%d"), daemon->namebuff, port);
|
||||
}
|
||||
@@ -626,9 +794,10 @@ int reload_servers(char *fname)
|
||||
serv->addr = addr;
|
||||
serv->source_addr = source_addr;
|
||||
serv->domain = NULL;
|
||||
serv->interface[0] = 0;
|
||||
serv->sfd = NULL;
|
||||
serv->flags = SERV_FROM_RESOLV;
|
||||
|
||||
serv->queries = serv->failed_queries = 0;
|
||||
gotone = 1;
|
||||
}
|
||||
|
||||
|
||||
1035
src/option.c
1035
src/option.c
File diff suppressed because it is too large
Load Diff
228
src/rfc1035.c
228
src/rfc1035.c
@@ -1,13 +1,17 @@
|
||||
/* dnsmasq is Copyright (c) 2000 - 2006 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991.
|
||||
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
@@ -32,7 +36,7 @@ static int extract_name(HEADER *header, size_t plen, unsigned char **pp,
|
||||
unsigned int label_type = l & 0xc0;
|
||||
if (label_type == 0xc0) /* pointer */
|
||||
{
|
||||
if ((size_t)(p - (unsigned char *)header + 1) >= plen)
|
||||
if ((size_t)(p - (unsigned char *)header) >= plen)
|
||||
return 0;
|
||||
|
||||
/* get offset */
|
||||
@@ -70,7 +74,7 @@ static int extract_name(HEADER *header, size_t plen, unsigned char **pp,
|
||||
/* output is \[x<hex>/siz]. which is digs+9 chars */
|
||||
if (cp - (unsigned char *)name + digs + 9 >= MAXDNAME)
|
||||
return 0;
|
||||
if ((size_t)(p - (unsigned char *)header + ((count-1)>>3) + 1) >= plen)
|
||||
if ((size_t)(p - (unsigned char *)header + ((count-1)>>3)) >= plen)
|
||||
return 0;
|
||||
|
||||
*cp++ = '\\';
|
||||
@@ -94,7 +98,7 @@ static int extract_name(HEADER *header, size_t plen, unsigned char **pp,
|
||||
{ /* label_type = 0 -> label. */
|
||||
if (cp - (unsigned char *)name + l + 1 >= MAXDNAME)
|
||||
return 0;
|
||||
if ((size_t)(p - (unsigned char *)header + 1) >= plen)
|
||||
if ((size_t)(p - (unsigned char *)header) >= plen)
|
||||
return 0;
|
||||
for(j=0; j<l; j++, p++)
|
||||
if (isExtract)
|
||||
@@ -223,7 +227,7 @@ static int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
|
||||
if (*name == '\\' && *(name+1) == '[' &&
|
||||
(*(name+2) == 'x' || *(name+2) == 'X'))
|
||||
{
|
||||
for (j = 0, cp1 = name+3; *cp1 && isxdigit(*cp1) && j < 32; cp1++, j++)
|
||||
for (j = 0, cp1 = name+3; *cp1 && isxdigit((int) *cp1) && j < 32; cp1++, j++)
|
||||
{
|
||||
char xdig[2];
|
||||
xdig[0] = *cp1;
|
||||
@@ -497,6 +501,50 @@ static int private_net(struct in_addr addr)
|
||||
((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 (zeroconf) */ ;
|
||||
}
|
||||
|
||||
static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, size_t qlen)
|
||||
{
|
||||
int i, qtype, qclass, rdlen;
|
||||
unsigned long ttl;
|
||||
|
||||
for (i = count; i != 0; i--)
|
||||
{
|
||||
if (!(p = skip_name(p, header, qlen)))
|
||||
return 0; /* bad packet */
|
||||
|
||||
GETSHORT(qtype, p);
|
||||
GETSHORT(qclass, p);
|
||||
GETLONG(ttl, p);
|
||||
GETSHORT(rdlen, p);
|
||||
|
||||
if ((qclass == C_IN) && (qtype == T_A))
|
||||
{
|
||||
struct doctor *doctor;
|
||||
struct in_addr addr;
|
||||
|
||||
/* alignment */
|
||||
memcpy(&addr, p, INADDRSZ);
|
||||
|
||||
for (doctor = daemon->doctors; doctor; doctor = doctor->next)
|
||||
if (is_same_net(doctor->in, addr, doctor->mask))
|
||||
{
|
||||
addr.s_addr &= ~doctor->mask.s_addr;
|
||||
addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
|
||||
/* Since we munged the data, the server it came from is no longer authoritative */
|
||||
header->aa = 0;
|
||||
memcpy(p, &addr, INADDRSZ);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
p += rdlen;
|
||||
|
||||
if ((size_t)(p - (unsigned char *)header) > qlen)
|
||||
return 0; /* bad packet */
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static int find_soa(HEADER *header, size_t qlen)
|
||||
{
|
||||
unsigned char *p;
|
||||
@@ -506,8 +554,8 @@ static int find_soa(HEADER *header, size_t qlen)
|
||||
|
||||
/* first move to NS section and find TTL from any SOA section */
|
||||
if (!(p = skip_questions(header, qlen)) ||
|
||||
!(p = skip_section(p, ntohs(header->ancount), header, qlen)))
|
||||
return 0; /* bad packet */
|
||||
!(p = do_doctor(p, ntohs(header->ancount), header, qlen)))
|
||||
return 0; /* bad packet */
|
||||
|
||||
for (i = ntohs(header->nscount); i != 0; i--)
|
||||
{
|
||||
@@ -544,52 +592,23 @@ static int find_soa(HEADER *header, size_t qlen)
|
||||
return 0; /* bad packet */
|
||||
}
|
||||
|
||||
if (daemon->doctors)
|
||||
for (i = ntohs(header->arcount); i != 0; i--)
|
||||
{
|
||||
if (!(p = skip_name(p, header, qlen)))
|
||||
return 0; /* bad packet */
|
||||
|
||||
GETSHORT(qtype, p);
|
||||
GETSHORT(qclass, p);
|
||||
GETLONG(ttl, p);
|
||||
GETSHORT(rdlen, p);
|
||||
|
||||
if ((qclass == C_IN) && (qtype == T_A))
|
||||
{
|
||||
struct doctor *doctor;
|
||||
struct in_addr addr;
|
||||
|
||||
/* alignment */
|
||||
memcpy(&addr, p, INADDRSZ);
|
||||
|
||||
for (doctor = daemon->doctors; doctor; doctor = doctor->next)
|
||||
if (is_same_net(doctor->in, addr, doctor->mask))
|
||||
{
|
||||
addr.s_addr &= ~doctor->mask.s_addr;
|
||||
addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
|
||||
/* Since we munged the data, the server it came from is no longer authoritative */
|
||||
header->aa = 0;
|
||||
memcpy(p, &addr, INADDRSZ);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
p += rdlen;
|
||||
|
||||
if ((size_t)(p - (unsigned char *)header) > qlen)
|
||||
return 0; /* bad packet */
|
||||
}
|
||||
|
||||
return found_soa ? minttl : 0;
|
||||
/* rewrite addresses in additioal section too */
|
||||
if (!do_doctor(p, ntohs(header->arcount), header, qlen))
|
||||
return 0;
|
||||
|
||||
if (!found_soa)
|
||||
minttl = daemon->neg_ttl;
|
||||
|
||||
return minttl;
|
||||
}
|
||||
|
||||
/* Note that the following code can create CNAME chains that don't point to a real record,
|
||||
either because of lack of memory, or lack of SOA records. These are treated by the cache code as
|
||||
expired and cleaned out that way. */
|
||||
void extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
|
||||
expired and cleaned out that way.
|
||||
Return 1 if we reject an address because it look like parct of dns-rebinding attack. */
|
||||
int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
|
||||
{
|
||||
unsigned char *p, *p1, *endrr;
|
||||
unsigned char *p, *p1, *endrr, *namep;
|
||||
int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
|
||||
unsigned long ttl = 0;
|
||||
struct all_addr addr;
|
||||
@@ -613,8 +632,9 @@ void extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
|
||||
int flags = header->rcode == NXDOMAIN ? F_NXDOMAIN : 0;
|
||||
unsigned long cttl = ULONG_MAX, attl;
|
||||
|
||||
namep = p;
|
||||
if (!extract_name(header, qlen, &p, name, 1))
|
||||
return; /* bad packet */
|
||||
return 0; /* bad packet */
|
||||
|
||||
GETSHORT(qtype, p);
|
||||
GETSHORT(qclass, p);
|
||||
@@ -635,12 +655,15 @@ void extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
|
||||
{
|
||||
cname_loop:
|
||||
if (!(p1 = skip_questions(header, qlen)))
|
||||
return;
|
||||
return 0;
|
||||
|
||||
for (j = ntohs(header->ancount); j != 0; j--)
|
||||
{
|
||||
if (!(res = extract_name(header, qlen, &p1, name, 0)))
|
||||
return; /* bad packet */
|
||||
unsigned char *tmp = namep;
|
||||
/* the loop body overwrites the original name, so get it back here. */
|
||||
if (!extract_name(header, qlen, &tmp, name, 1) ||
|
||||
!(res = extract_name(header, qlen, &p1, name, 0)))
|
||||
return 0; /* bad packet */
|
||||
|
||||
GETSHORT(aqtype, p1);
|
||||
GETSHORT(aqclass, p1);
|
||||
@@ -655,12 +678,12 @@ void extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
|
||||
if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == T_PTR))
|
||||
{
|
||||
if (!extract_name(header, qlen, &p1, name, 1))
|
||||
return;
|
||||
return 0;
|
||||
|
||||
if (aqtype == T_CNAME)
|
||||
{
|
||||
if (!cname_count--)
|
||||
return; /* looped CNAMES */
|
||||
return 0; /* looped CNAMES */
|
||||
goto cname_loop;
|
||||
}
|
||||
|
||||
@@ -670,7 +693,7 @@ void extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
|
||||
|
||||
p1 = endrr;
|
||||
if ((size_t)(p1 - (unsigned char *)header) > qlen)
|
||||
return; /* bad packet */
|
||||
return 0; /* bad packet */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -710,12 +733,12 @@ void extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
|
||||
{
|
||||
cname_loop1:
|
||||
if (!(p1 = skip_questions(header, qlen)))
|
||||
return;
|
||||
return 0;
|
||||
|
||||
for (j = ntohs(header->ancount); j != 0; j--)
|
||||
{
|
||||
if (!(res = extract_name(header, qlen, &p1, name, 0)))
|
||||
return; /* bad packet */
|
||||
return 0; /* bad packet */
|
||||
|
||||
GETSHORT(aqtype, p1);
|
||||
GETSHORT(aqclass, p1);
|
||||
@@ -728,7 +751,7 @@ void extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
|
||||
if (aqtype == T_CNAME)
|
||||
{
|
||||
if (!cname_count--)
|
||||
return; /* looped CNAMES */
|
||||
return 0; /* looped CNAMES */
|
||||
newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD);
|
||||
if (newc && cpp)
|
||||
{
|
||||
@@ -741,7 +764,7 @@ void extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
|
||||
cttl = attl;
|
||||
|
||||
if (!extract_name(header, qlen, &p1, name, 1))
|
||||
return;
|
||||
return 0;
|
||||
goto cname_loop1;
|
||||
}
|
||||
else
|
||||
@@ -749,6 +772,13 @@ void extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
|
||||
found = 1;
|
||||
/* copy address into aligned storage */
|
||||
memcpy(&addr, p1, addrlen);
|
||||
|
||||
/* check for returned address in private space */
|
||||
if ((daemon->options & OPT_NO_REBIND) &&
|
||||
(flags & F_IPV4) &&
|
||||
private_net(addr.addr.addr4))
|
||||
return 1;
|
||||
|
||||
newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD);
|
||||
if (newc && cpp)
|
||||
{
|
||||
@@ -761,7 +791,7 @@ void extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
|
||||
|
||||
p1 = endrr;
|
||||
if ((size_t)(p1 - (unsigned char *)header) > qlen)
|
||||
return; /* bad packet */
|
||||
return 0; /* bad packet */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -773,7 +803,7 @@ void extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
|
||||
ttl = find_soa(header, qlen);
|
||||
}
|
||||
/* If there's no SOA to get the TTL from, but there is a CNAME
|
||||
pointing at this, inherit it's TTL */
|
||||
pointing at this, inherit its TTL */
|
||||
if (ttl || cpp)
|
||||
{
|
||||
newc = cache_insert(name, NULL, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags);
|
||||
@@ -787,7 +817,11 @@ void extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
|
||||
}
|
||||
}
|
||||
|
||||
cache_end_insert();
|
||||
/* Don't put stuff from a truncated packet into the cache, but do everything else */
|
||||
if (!header->tc)
|
||||
cache_end_insert();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If the packet holds exactly one query
|
||||
@@ -844,7 +878,7 @@ size_t setup_reply(HEADER *header, size_t qlen,
|
||||
header->ancount = htons(0); /* no answers unless changed below */
|
||||
if (flags == F_NEG)
|
||||
header->rcode = SERVFAIL; /* couldn't get memory */
|
||||
else if (flags == F_NOERR || flags == F_QUERY)
|
||||
else if (flags == F_NOERR)
|
||||
header->rcode = NOERROR; /* empty domain */
|
||||
else if (flags == F_NXDOMAIN)
|
||||
header->rcode = NXDOMAIN;
|
||||
@@ -1010,6 +1044,16 @@ static int add_resource_record(HEADER *header, char *limit, int *truncp, unsigne
|
||||
memcpy(p, sval, usval);
|
||||
p += usval;
|
||||
break;
|
||||
|
||||
case 'z':
|
||||
sval = va_arg(ap, char *);
|
||||
usval = sval ? strlen(sval) : 0;
|
||||
if (usval > 255)
|
||||
usval = 255;
|
||||
*p++ = (unsigned char)usval;
|
||||
memcpy(p, sval, usval);
|
||||
p += usval;
|
||||
break;
|
||||
}
|
||||
|
||||
va_end(ap); /* clean up variable argument pointer */
|
||||
@@ -1111,7 +1155,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, 0, NULL, 0);
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<TXT>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL,
|
||||
T_TXT, t->class, "t", t->len, t->txt))
|
||||
@@ -1150,7 +1194,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_IPV4 | F_REVERSE | F_CONFIG, intr->name, &addr, 0, NULL, 0);
|
||||
log_query(F_IPV4 | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL,
|
||||
T_PTR, C_IN, "d", intr->name))
|
||||
@@ -1162,7 +1206,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_BIGNAME, name, NULL, 0, NULL, 0);
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<PTR>");
|
||||
for (ptr = daemon->ptr; ptr; ptr = ptr->next)
|
||||
if (hostname_isequal(name, ptr->name) &&
|
||||
add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
@@ -1186,7 +1230,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
if (crecp->flags & F_NXDOMAIN)
|
||||
nxdomain = 1;
|
||||
if (!dryrun)
|
||||
log_query(crecp->flags & ~F_FORWARD, name, &addr, 0, NULL, 0);
|
||||
log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
|
||||
}
|
||||
else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)
|
||||
{
|
||||
@@ -1203,8 +1247,8 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
else
|
||||
ttl = crecp->ttd - now;
|
||||
|
||||
log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
|
||||
0, daemon->addn_hosts, crecp->uid);
|
||||
log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
|
||||
record_source(daemon->addn_hosts, crecp->uid));
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL,
|
||||
T_PTR, C_IN, "d", cache_get_name(crecp)))
|
||||
@@ -1221,7 +1265,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
nxdomain = 1;
|
||||
if (!dryrun)
|
||||
log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN,
|
||||
name, &addr, 0, NULL, 0);
|
||||
name, &addr, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1245,7 +1289,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, 0, NULL, 0);
|
||||
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL, type, C_IN, "4", &addr))
|
||||
anscount++;
|
||||
@@ -1268,10 +1312,10 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
if (!dryrun)
|
||||
{
|
||||
if ((addr.addr.addr4 = get_ifaddr(intr->intr)).s_addr == (in_addr_t) -1)
|
||||
log_query(F_FORWARD | F_CONFIG | F_IPV4 | F_NEG, name, NULL, 0, NULL, 0);
|
||||
log_query(F_FORWARD | F_CONFIG | F_IPV4 | F_NEG, name, NULL, NULL);
|
||||
else
|
||||
{
|
||||
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, 0, NULL, 0);
|
||||
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL, type, C_IN, "4", &addr))
|
||||
anscount++;
|
||||
@@ -1313,7 +1357,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
{
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(crecp->flags, name, NULL, 0, daemon->addn_hosts, crecp->uid);
|
||||
log_query(crecp->flags, name, NULL, record_source(daemon->addn_hosts, crecp->uid));
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, crecp->ttd - now, &nameoffset,
|
||||
T_CNAME, C_IN, "d", cache_get_name(crecp->addr.cname.cache)))
|
||||
anscount++;
|
||||
@@ -1330,7 +1374,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
if (crecp->flags & F_NXDOMAIN)
|
||||
nxdomain = 1;
|
||||
if (!dryrun)
|
||||
log_query(crecp->flags, name, NULL, 0, NULL, 0);
|
||||
log_query(crecp->flags, name, NULL, NULL);
|
||||
}
|
||||
else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)
|
||||
{
|
||||
@@ -1355,7 +1399,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
ttl = crecp->ttd - now;
|
||||
|
||||
log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr,
|
||||
0, daemon->addn_hosts, crecp->uid);
|
||||
record_source(daemon->addn_hosts, crecp->uid));
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL, type, C_IN,
|
||||
type == T_A ? "4" : "6", &crecp->addr))
|
||||
@@ -1376,7 +1420,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
if (!dryrun)
|
||||
{
|
||||
unsigned int offset;
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_IPV4, name, NULL, 0, NULL, 0);
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<MX>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
|
||||
&offset, T_MX, C_IN, "sd", rec->weight, rec->target))
|
||||
{
|
||||
@@ -1393,7 +1437,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_IPV4, name, NULL, 0, NULL, 0);
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<MX>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
|
||||
T_MX, C_IN, "sd", 1,
|
||||
(daemon->options & OPT_SELFMX) ? name : daemon->mxtarget))
|
||||
@@ -1413,7 +1457,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
if (!dryrun)
|
||||
{
|
||||
unsigned int offset;
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_IPV6, name, NULL, 0, NULL, 0);
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<SRV>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
|
||||
&offset, T_SRV, C_IN, "sssd",
|
||||
rec->priority, rec->weight, rec->srvport, rec->target))
|
||||
@@ -1429,9 +1473,27 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
log_query(F_CONFIG | F_NEG, name, NULL, 0, NULL, 0);
|
||||
log_query(F_CONFIG | F_NEG, name, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (qtype == T_NAPTR || qtype == T_ANY)
|
||||
{
|
||||
struct naptr *na;
|
||||
for (na = daemon->naptr; na; na = na->next)
|
||||
if (hostname_isequal(name, na->name))
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<NAPTR>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
|
||||
NULL, T_NAPTR, C_IN, "sszzzd",
|
||||
na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (qtype == T_MAILB)
|
||||
ans = 1, nxdomain = 1;
|
||||
@@ -1440,7 +1502,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
log_query(F_CONFIG | F_NEG, name, &addr, 0, NULL, 0);
|
||||
log_query(F_CONFIG | F_NEG, name, &addr, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
385
src/rfc2131.c
385
src/rfc2131.c
@@ -2,12 +2,16 @@
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991.
|
||||
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
@@ -52,6 +56,7 @@
|
||||
#define SUBOPT_REMOTE_ID 2
|
||||
#define SUBOPT_SUBNET_SELECT 5 /* RFC 3527 */
|
||||
#define SUBOPT_SUBSCR_ID 6 /* RFC 3393 */
|
||||
#define SUBOPT_SERVER_OR 11 /* RFC 5107 */
|
||||
|
||||
#define DHCPDISCOVER 1
|
||||
#define DHCPOFFER 2
|
||||
@@ -64,11 +69,11 @@
|
||||
|
||||
#define have_config(config, mask) ((config) && ((config)->flags & (mask)))
|
||||
#define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
|
||||
#define option_ptr(opt) ((void *)&(((unsigned char *)(opt))[2]))
|
||||
#define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)]))
|
||||
|
||||
static int sanitise(unsigned char *opt, char *buf);
|
||||
static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config,
|
||||
struct dhcp_lease *lease, unsigned char *opt, time_t now);
|
||||
static struct in_addr server_id(struct dhcp_context *context, struct in_addr override);
|
||||
static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt);
|
||||
static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val);
|
||||
static void option_put_string(struct dhcp_packet *mess, unsigned char *end,
|
||||
int opt, char *string, int null_term);
|
||||
@@ -79,7 +84,8 @@ static void log_packet(char *type, void *addr,
|
||||
static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize);
|
||||
static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize);
|
||||
static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *netid);
|
||||
static void clear_packet(struct dhcp_packet *mess, unsigned char *end);
|
||||
static void clear_packet(struct dhcp_packet *mess, unsigned char *end, unsigned char *agent_id);
|
||||
static void restore_agent_id(unsigned char *agent_id, struct dhcp_packet *mess, unsigned char *real_end);
|
||||
static void do_options(struct dhcp_context *context,
|
||||
struct dhcp_packet *mess,
|
||||
unsigned char *real_end,
|
||||
@@ -95,7 +101,7 @@ static unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwad
|
||||
static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
|
||||
|
||||
|
||||
size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
size_t sz, time_t now, int unicast_dest, int *is_inform)
|
||||
{
|
||||
unsigned char *opt, *clid = NULL;
|
||||
@@ -104,7 +110,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
struct dhcp_mac *mac;
|
||||
struct dhcp_netid_list *id_list;
|
||||
int clid_len = 0, ignore = 0, do_classes = 0, selecting = 0;
|
||||
struct dhcp_packet *mess = daemon->dhcp_packet.iov_base;
|
||||
struct dhcp_packet *mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
|
||||
unsigned char *end = (unsigned char *)(mess + 1);
|
||||
char *hostname = NULL, *offer_hostname = NULL, *client_hostname = NULL;
|
||||
int hostname_auth = 0, borken_opt = 0;
|
||||
@@ -113,16 +119,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
unsigned int time;
|
||||
struct dhcp_config *config;
|
||||
struct dhcp_netid *netid = NULL;
|
||||
struct in_addr subnet_addr, fallback;
|
||||
struct in_addr subnet_addr, fallback, override;
|
||||
unsigned short fuzz = 0;
|
||||
unsigned int mess_type = 0;
|
||||
unsigned char fqdn_flags = 0;
|
||||
unsigned char *agent_id = NULL;
|
||||
unsigned char *emac = NULL;
|
||||
int emac_len;
|
||||
int emac_len = 0;
|
||||
struct dhcp_netid known_id;
|
||||
|
||||
subnet_addr.s_addr = 0;
|
||||
subnet_addr.s_addr = override.s_addr = 0;
|
||||
|
||||
if (mess->op != BOOTREQUEST || mess->hlen > DHCP_CHADDR_MAX)
|
||||
return 0;
|
||||
@@ -153,7 +159,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
|
||||
if (expand_buf(&daemon->dhcp_packet, size))
|
||||
{
|
||||
mess = daemon->dhcp_packet.iov_base;
|
||||
mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
|
||||
end = ((unsigned char *)mess) + size;
|
||||
}
|
||||
}
|
||||
@@ -180,8 +186,12 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
}
|
||||
|
||||
/* look for RFC3527 Link selection sub-option */
|
||||
if ((sopt = option_find1(option_ptr(opt), option_ptr(opt) + option_len(opt), SUBOPT_SUBNET_SELECT, INADDRSZ)))
|
||||
if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SUBNET_SELECT, INADDRSZ)))
|
||||
subnet_addr = option_addr(sopt);
|
||||
|
||||
/* look for RFC5107 server-identifier-override */
|
||||
if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SERVER_OR, INADDRSZ)))
|
||||
override = option_addr(sopt);
|
||||
|
||||
/* if a circuit-id or remote-is option is provided, exact-match to options. */
|
||||
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
||||
@@ -197,9 +207,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
else
|
||||
continue;
|
||||
|
||||
if ((sopt = option_find1(option_ptr(opt), option_ptr(opt) + option_len(opt), search, 1)) &&
|
||||
if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), search, 1)) &&
|
||||
vendor->len == option_len(sopt) &&
|
||||
memcmp(option_ptr(sopt), vendor->data, vendor->len) == 0)
|
||||
memcmp(option_ptr(sopt, 0), vendor->data, vendor->len) == 0)
|
||||
{
|
||||
vendor->netid.next = netid;
|
||||
netid = &vendor->netid;
|
||||
@@ -216,7 +226,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
if ((opt = option_find(mess, sz, OPTION_CLIENT_ID, 1)))
|
||||
{
|
||||
clid_len = option_len(opt);
|
||||
clid = option_ptr(opt);
|
||||
clid = option_ptr(opt, 0);
|
||||
}
|
||||
|
||||
/* do we have a lease in store? */
|
||||
@@ -394,7 +404,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
else
|
||||
{
|
||||
if (!(lease = lease_find_by_client(mess->chaddr, mess->hlen, mess->htype, NULL, 0)) ||
|
||||
!address_available(context, lease->addr))
|
||||
!address_available(context, lease->addr, netid))
|
||||
{
|
||||
if (lease)
|
||||
{
|
||||
@@ -412,12 +422,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
if (!message &&
|
||||
!lease &&
|
||||
(!(lease = lease_allocate(mess->yiaddr))))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("Limit of %d leases exceeded."), daemon->dhcp_max);
|
||||
message = _("no leases left");
|
||||
}
|
||||
|
||||
if (!message && !(context = narrow_context(context, mess->yiaddr)))
|
||||
message = _("no leases left");
|
||||
|
||||
if (!message && !(context = narrow_context(context, mess->yiaddr, netid)))
|
||||
message = _("wrong network");
|
||||
|
||||
if (!message)
|
||||
@@ -433,9 +440,13 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0);
|
||||
if (hostname)
|
||||
lease_set_hostname(lease, hostname, daemon->domain_suffix, 1);
|
||||
lease_set_expires(lease, 0xffffffff, now); /* infinite lease */
|
||||
/* infinite lease unless nailed in dhcp-host line. */
|
||||
lease_set_expires(lease,
|
||||
have_config(config, CONFIG_TIME) ? config->lease_time : 0xffffffff,
|
||||
now);
|
||||
lease_set_interface(lease, int_index);
|
||||
|
||||
clear_packet(mess, end);
|
||||
clear_packet(mess, end, NULL);
|
||||
do_options(context, mess, end, NULL,
|
||||
hostname, netid, subnet_addr, 0, 0, NULL);
|
||||
}
|
||||
@@ -451,7 +462,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
/* http://tools.ietf.org/wg/dhc/draft-ietf-dhc-fqdn-option/draft-ietf-dhc-fqdn-option-10.txt */
|
||||
int len = option_len(opt);
|
||||
char *pq = daemon->dhcp_buff;
|
||||
unsigned char *pp, *op = option_ptr(opt);
|
||||
unsigned char *pp, *op = option_ptr(opt, 0);
|
||||
|
||||
fqdn_flags = *op;
|
||||
len -= 3;
|
||||
@@ -492,7 +503,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
else if ((opt = option_find(mess, sz, OPTION_HOSTNAME, 1)))
|
||||
{
|
||||
int len = option_len(opt);
|
||||
memcpy(daemon->dhcp_buff, option_ptr(opt), len);
|
||||
memcpy(daemon->dhcp_buff, option_ptr(opt, 0), len);
|
||||
/* Microsoft clients are broken, and need zero-terminated strings
|
||||
in options. We detect this state here, and do the same in
|
||||
any options we send */
|
||||
@@ -529,8 +540,14 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0,
|
||||
mess->chaddr, mess->hlen,
|
||||
mess->htype, hostname);
|
||||
if (!have_config(new, CONFIG_CLID) && !have_config(new, CONFIG_HWADDR))
|
||||
config = new;
|
||||
if (new && !have_config(new, CONFIG_CLID) && !have_config(new, CONFIG_HWADDR))
|
||||
{
|
||||
config = new;
|
||||
/* set "known" tag for known hosts */
|
||||
known_id.net = "known";
|
||||
known_id.next = netid;
|
||||
netid = &known_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -554,7 +571,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
|
||||
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
|
||||
{
|
||||
unsigned char *ucp = option_ptr(opt);
|
||||
unsigned char *ucp = option_ptr(opt, 0);
|
||||
int tmp, j;
|
||||
for (j = 0; j < option_len(opt); j += ucp[j] + 1);
|
||||
if (j == option_len(opt))
|
||||
@@ -573,6 +590,15 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
mopt = OPTION_VENDOR_ID;
|
||||
else if (vendor->match_type == MATCH_USER)
|
||||
mopt = OPTION_USER_CLASS;
|
||||
else if (vendor->match_type == MATCH_OPTION)
|
||||
{
|
||||
if (option_find(mess, sz, vendor->option, 1))
|
||||
{
|
||||
vendor->netid.next = netid;
|
||||
netid = &vendor->netid;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
|
||||
@@ -580,7 +606,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i <= (option_len(opt) - vendor->len); i++)
|
||||
if (memcmp(vendor->data, option_ptr(opt)+i, vendor->len) == 0)
|
||||
if (memcmp(vendor->data, option_ptr(opt, i), vendor->len) == 0)
|
||||
{
|
||||
vendor->netid.next = netid;
|
||||
netid = &vendor->netid;
|
||||
@@ -612,7 +638,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS, 0)))
|
||||
{
|
||||
req_options = (unsigned char *)daemon->dhcp_buff2;
|
||||
memcpy(req_options, option_ptr(opt), option_len(opt));
|
||||
memcpy(req_options, option_ptr(opt, 0), option_len(opt));
|
||||
req_options[option_len(opt)] = OPTION_END;
|
||||
}
|
||||
|
||||
@@ -620,16 +646,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
{
|
||||
case DHCPDECLINE:
|
||||
if (!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
|
||||
(context->local.s_addr != option_addr(opt).s_addr))
|
||||
option_addr(opt).s_addr != server_id(context, override).s_addr)
|
||||
return 0;
|
||||
|
||||
|
||||
/* sanitise any message. Paranoid? Moi? */
|
||||
sanitise(option_find(mess, sz, OPTION_MESSAGE, 1), daemon->dhcp_buff);
|
||||
|
||||
if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
|
||||
return 0;
|
||||
|
||||
log_packet("DECLINE", option_ptr(opt), emac, emac_len, iface_name, daemon->dhcp_buff);
|
||||
log_packet("DECLINE", option_ptr(opt, 0), emac, emac_len, iface_name, daemon->dhcp_buff);
|
||||
|
||||
if (lease && lease->addr.s_addr == option_addr(opt).s_addr)
|
||||
lease_prune(lease, now);
|
||||
@@ -651,9 +677,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
return 0;
|
||||
|
||||
case DHCPRELEASE:
|
||||
if (!(context = narrow_context(context, mess->ciaddr)) ||
|
||||
if (!(context = narrow_context(context, mess->ciaddr, netid)) ||
|
||||
!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
|
||||
(context->local.s_addr != option_addr(opt).s_addr))
|
||||
option_addr(opt).s_addr != server_id(context, override).s_addr)
|
||||
return 0;
|
||||
|
||||
if (lease && lease->addr.s_addr == mess->ciaddr.s_addr)
|
||||
@@ -675,10 +701,11 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
{
|
||||
struct in_addr addr, conf;
|
||||
|
||||
addr.s_addr = conf.s_addr = 0;
|
||||
|
||||
if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
|
||||
addr = option_addr(opt);
|
||||
|
||||
conf.s_addr = 0;
|
||||
if (have_config(config, CONFIG_ADDR))
|
||||
{
|
||||
char *addrs = inet_ntoa(config->addr);
|
||||
@@ -709,9 +736,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
|
||||
if (conf.s_addr)
|
||||
mess->yiaddr = conf;
|
||||
else if (lease && address_available(context, lease->addr))
|
||||
else if (lease && address_available(context, lease->addr, netid))
|
||||
mess->yiaddr = lease->addr;
|
||||
else if (opt && address_available(context, addr) && !lease_find_by_addr(addr) &&
|
||||
else if (opt && address_available(context, addr, netid) && !lease_find_by_addr(addr) &&
|
||||
!config_find_by_address(daemon->dhcp_conf, addr))
|
||||
mess->yiaddr = addr;
|
||||
else if (emac_len == 0)
|
||||
@@ -720,9 +747,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
message = _("no address available");
|
||||
}
|
||||
|
||||
log_packet("DISCOVER", opt ? option_ptr(opt) : NULL, emac, emac_len, iface_name, message);
|
||||
log_packet("DISCOVER", opt ? option_ptr(opt, 0) : NULL, emac, emac_len, iface_name, message);
|
||||
|
||||
if (message || !(context = narrow_context(context, mess->yiaddr)))
|
||||
if (message || !(context = narrow_context(context, mess->yiaddr, netid)))
|
||||
return 0;
|
||||
|
||||
log_packet("OFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL);
|
||||
@@ -733,10 +760,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
netid = &context->netid;
|
||||
}
|
||||
|
||||
time = calc_time(context, config, lease, option_find(mess, sz, OPTION_LEASE_TIME, 4), now);
|
||||
clear_packet(mess, end);
|
||||
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
|
||||
clear_packet(mess, end, agent_id);
|
||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(context->local.s_addr));
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override).s_addr));
|
||||
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
|
||||
/* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
|
||||
if (time != 0xffffffff)
|
||||
@@ -765,13 +792,21 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
/* SELECTING */
|
||||
selecting = 1;
|
||||
|
||||
for (; context; context = context->current)
|
||||
if (context->local.s_addr == option_addr(opt).s_addr)
|
||||
break;
|
||||
if (override.s_addr != 0)
|
||||
{
|
||||
if (option_addr(opt).s_addr != override.s_addr)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; context; context = context->current)
|
||||
if (context->local.s_addr == option_addr(opt).s_addr)
|
||||
break;
|
||||
|
||||
if (!context)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!context)
|
||||
return 0;
|
||||
|
||||
/* If a lease exists for this host and another address, squash it. */
|
||||
if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
|
||||
{
|
||||
@@ -786,7 +821,12 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
return 0;
|
||||
|
||||
if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
|
||||
message = _("wrong address");
|
||||
{
|
||||
message = _("wrong address");
|
||||
/* avoid loops when client brain-dead */
|
||||
lease_prune(lease, now);
|
||||
lease = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -820,7 +860,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
if (context->router.s_addr == config->addr.s_addr)
|
||||
break;
|
||||
|
||||
if (!(context = narrow_context(context, mess->yiaddr)))
|
||||
if (!(context = narrow_context(context, mess->yiaddr, netid)))
|
||||
{
|
||||
/* If a machine moves networks whilst it has a lease, we catch that here. */
|
||||
message = _("wrong network");
|
||||
@@ -829,7 +869,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
}
|
||||
|
||||
/* Check for renewal of a lease which is outside the allowed range. */
|
||||
else if (!address_available(context, mess->yiaddr) &&
|
||||
else if (!address_available(context, mess->yiaddr, netid) &&
|
||||
(!have_config(config, CONFIG_ADDR) || config->addr.s_addr != mess->yiaddr.s_addr))
|
||||
message = _("address not available");
|
||||
|
||||
@@ -868,11 +908,13 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
log_packet("NAK", &mess->yiaddr, emac, emac_len, iface_name, message);
|
||||
|
||||
mess->yiaddr.s_addr = 0;
|
||||
clear_packet(mess, end);
|
||||
clear_packet(mess, end, agent_id);
|
||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPNAK);
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ,
|
||||
ntohl(context ? context->local.s_addr : fallback.s_addr));
|
||||
ntohl(server_id(context, override).s_addr ? server_id(context, override).s_addr : fallback.s_addr));
|
||||
option_put_string(mess, end, OPTION_MESSAGE, message, borken_opt);
|
||||
/* DHCPNAK gets agent-id too */
|
||||
restore_agent_id(agent_id, mess, end);
|
||||
/* This fixes a problem with the DHCP spec, broadcasting a NAK to a host on
|
||||
a distant subnet which unicast a REQ to us won't work. */
|
||||
if (!unicast_dest || mess->giaddr.s_addr != 0 ||
|
||||
@@ -891,7 +933,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
|
||||
{
|
||||
int len = option_len(opt);
|
||||
unsigned char *ucp = option_ptr(opt);
|
||||
unsigned char *ucp = option_ptr(opt, 0);
|
||||
/* If the user-class option started as counted strings, the first byte will be zero. */
|
||||
if (len != 0 && ucp[0] == 0)
|
||||
ucp++, len--;
|
||||
@@ -906,7 +948,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
if ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 1)))
|
||||
{
|
||||
int len = option_len(opt);
|
||||
unsigned char *ucp = option_ptr(opt);
|
||||
unsigned char *ucp = option_ptr(opt, 0);
|
||||
free(lease->vendorclass);
|
||||
if ((lease->vendorclass = whine_malloc(len+1)))
|
||||
{
|
||||
@@ -929,7 +971,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
netid = &context->netid;
|
||||
}
|
||||
|
||||
time = calc_time(context, config, NULL, option_find(mess, sz, OPTION_LEASE_TIME, 4), now);
|
||||
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
|
||||
lease_set_hwaddr(lease, mess->chaddr, clid, mess->hlen, mess->htype, clid_len);
|
||||
|
||||
/* if all the netids in the ignore_name list are present, ignore client-supplied name */
|
||||
@@ -945,12 +987,18 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
lease_set_hostname(lease, hostname, daemon->domain_suffix, hostname_auth);
|
||||
|
||||
lease_set_expires(lease, time, now);
|
||||
|
||||
lease_set_interface(lease, int_index);
|
||||
|
||||
if (override.s_addr != 0)
|
||||
lease->override = override;
|
||||
else
|
||||
override = lease->override;
|
||||
|
||||
log_packet("ACK", &mess->yiaddr, emac, emac_len, iface_name, hostname);
|
||||
|
||||
clear_packet(mess, end);
|
||||
clear_packet(mess, end, agent_id);
|
||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(context->local.s_addr));
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override).s_addr));
|
||||
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
|
||||
if (time != 0xffffffff)
|
||||
{
|
||||
@@ -972,7 +1020,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
log_packet("INFORM", &mess->ciaddr, emac, emac_len, iface_name, message);
|
||||
|
||||
if (message || mess->ciaddr.s_addr == 0 ||
|
||||
!(context = narrow_context(context, mess->ciaddr)))
|
||||
!(context = narrow_context(context, mess->ciaddr, netid)))
|
||||
return 0;
|
||||
|
||||
/* Find a least based on IP address if we didn't
|
||||
@@ -993,9 +1041,14 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
netid = &context->netid;
|
||||
}
|
||||
|
||||
clear_packet(mess, end);
|
||||
if (lease && override.s_addr != 0)
|
||||
lease->override = override;
|
||||
else
|
||||
override = lease->override;
|
||||
|
||||
clear_packet(mess, end, agent_id);
|
||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(context->local.s_addr));
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override).s_addr));
|
||||
|
||||
if (lease)
|
||||
{
|
||||
@@ -1004,7 +1057,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
|
||||
else
|
||||
time = (unsigned int)difftime(lease->expires, now);
|
||||
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
|
||||
lease_set_interface(lease, int_index);
|
||||
}
|
||||
|
||||
do_options(context, mess, end, req_options, hostname,
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, agent_id);
|
||||
|
||||
@@ -1050,8 +1105,7 @@ static unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwad
|
||||
return hwaddr;
|
||||
}
|
||||
|
||||
static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config,
|
||||
struct dhcp_lease *lease, unsigned char *opt, time_t now)
|
||||
static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt)
|
||||
{
|
||||
unsigned int time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time;
|
||||
|
||||
@@ -1063,21 +1117,18 @@ static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *
|
||||
if (time == 0xffffffff || (req_time != 0xffffffff && req_time < time))
|
||||
time = req_time;
|
||||
}
|
||||
else if (lease && lease->expires != 0 && difftime(lease->expires, now) > 0.0)
|
||||
{
|
||||
unsigned int lease_time = (unsigned int)difftime(lease->expires, now);
|
||||
|
||||
/* put a floor on lease-remaining time. */
|
||||
if (lease_time < 360 )
|
||||
lease_time = 360;
|
||||
|
||||
if (time > lease_time)
|
||||
time = lease_time;
|
||||
}
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
static struct in_addr server_id(struct dhcp_context *context, struct in_addr override)
|
||||
{
|
||||
if (override.s_addr != 0)
|
||||
return override;
|
||||
else
|
||||
return context->local;
|
||||
}
|
||||
|
||||
static int sanitise(unsigned char *opt, char *buf)
|
||||
{
|
||||
char *p;
|
||||
@@ -1088,12 +1139,12 @@ static int sanitise(unsigned char *opt, char *buf)
|
||||
if (!opt)
|
||||
return 0;
|
||||
|
||||
p = option_ptr(opt);
|
||||
p = option_ptr(opt, 0);
|
||||
|
||||
for (i = option_len(opt); i > 0; i--)
|
||||
{
|
||||
char c = *p++;
|
||||
if (isprint(c))
|
||||
if (isprint((int)c))
|
||||
*buf++ = c;
|
||||
}
|
||||
*buf = 0; /* add terminator */
|
||||
@@ -1138,27 +1189,27 @@ static void log_options(unsigned char *start)
|
||||
|
||||
static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize)
|
||||
{
|
||||
while (*p != OPTION_END)
|
||||
while (1)
|
||||
{
|
||||
if (p >= end)
|
||||
return NULL; /* malformed packet */
|
||||
if (p > end)
|
||||
return NULL;
|
||||
else if (*p == OPTION_END)
|
||||
return opt == OPTION_END ? p : NULL;
|
||||
else if (*p == OPTION_PAD)
|
||||
p++;
|
||||
else
|
||||
{
|
||||
int opt_len;
|
||||
if (p >= end - 2)
|
||||
if (p > end - 2)
|
||||
return NULL; /* malformed packet */
|
||||
opt_len = option_len(p);
|
||||
if (p >= end - (2 + opt_len))
|
||||
if (p > end - (2 + opt_len))
|
||||
return NULL; /* malformed packet */
|
||||
if (*p == opt && opt_len >= minsize)
|
||||
return p;
|
||||
p += opt_len + 2;
|
||||
}
|
||||
}
|
||||
|
||||
return opt == OPTION_END ? p : NULL;
|
||||
}
|
||||
|
||||
static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize)
|
||||
@@ -1192,7 +1243,7 @@ static struct in_addr option_addr(unsigned char *opt)
|
||||
/* struct in_addr is network byte order */
|
||||
struct in_addr ret;
|
||||
|
||||
memcpy(&ret, option_ptr(opt), INADDRSZ);
|
||||
memcpy(&ret, option_ptr(opt, 0), INADDRSZ);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1202,7 +1253,7 @@ static unsigned int option_uint(unsigned char *opt, int size)
|
||||
/* this worries about unaligned data and byte order */
|
||||
unsigned int ret = 0;
|
||||
int i;
|
||||
unsigned char *p = option_ptr(opt);
|
||||
unsigned char *p = option_ptr(opt, 0);
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
ret = (ret << 8) | *p++;
|
||||
@@ -1236,6 +1287,7 @@ static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *neti
|
||||
unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
|
||||
unsigned char *overload;
|
||||
size_t ret;
|
||||
struct dhcp_netid_list *id_list;
|
||||
|
||||
/* We do logging too */
|
||||
if (netid && (daemon->options & OPT_LOG_OPTS))
|
||||
@@ -1270,9 +1322,14 @@ static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *neti
|
||||
}
|
||||
|
||||
*p++ = OPTION_END;
|
||||
|
||||
if (daemon->options & OPT_LOG_OPTS)
|
||||
log_options(&mess->options[0] + sizeof(u32));
|
||||
|
||||
for (id_list = daemon->force_broadcast; id_list; id_list = id_list->next)
|
||||
if (match_netid(id_list->list, netid, 0))
|
||||
mess->flags |= htons(0x8000); /* force broadcast */
|
||||
|
||||
ret = (size_t)(p - (unsigned char *)mess);
|
||||
|
||||
if (ret < MIN_PACKETSZ)
|
||||
@@ -1435,7 +1492,7 @@ static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt)
|
||||
if (dopt->vendor_class)
|
||||
len = strlen((char *)dopt->vendor_class);
|
||||
for (i = 0; i <= (option_len(opt) - len); i++)
|
||||
if (len == 0 || memcmp(dopt->vendor_class, option_ptr(opt)+i, len) == 0)
|
||||
if (len == 0 || memcmp(dopt->vendor_class, option_ptr(opt, i), len) == 0)
|
||||
{
|
||||
dopt->flags |= DHOPT_VENDOR_MATCH;
|
||||
break;
|
||||
@@ -1444,14 +1501,29 @@ static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt)
|
||||
}
|
||||
}
|
||||
|
||||
static void clear_packet(struct dhcp_packet *mess, unsigned char *end)
|
||||
static void clear_packet(struct dhcp_packet *mess, unsigned char *end, unsigned char *agent_id)
|
||||
{
|
||||
/* don't clear agent_id */
|
||||
if (agent_id)
|
||||
end = agent_id;
|
||||
|
||||
memset(mess->sname, 0, sizeof(mess->sname));
|
||||
memset(mess->file, 0, sizeof(mess->file));
|
||||
memset(&mess->options[0] + sizeof(u32), 0, end - (&mess->options[0] + sizeof(u32)));
|
||||
mess->siaddr.s_addr = 0;
|
||||
}
|
||||
|
||||
static void restore_agent_id(unsigned char *agent_id, struct dhcp_packet *mess, unsigned char *real_end)
|
||||
{
|
||||
if (agent_id)
|
||||
{
|
||||
unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
|
||||
memmove(p, agent_id, real_end - agent_id);
|
||||
p += real_end - agent_id;
|
||||
memset(p, 0, real_end - p); /* in case of overlap */
|
||||
}
|
||||
}
|
||||
|
||||
static void do_options(struct dhcp_context *context,
|
||||
struct dhcp_packet *mess,
|
||||
unsigned char *real_end,
|
||||
@@ -1468,6 +1540,7 @@ static void do_options(struct dhcp_context *context,
|
||||
unsigned char *p, *end = agent_id ? agent_id : real_end;
|
||||
int i, len, force_encap = 0;
|
||||
unsigned char f0 = 0, s0 = 0;
|
||||
int done_file = 0, done_server = 0;
|
||||
|
||||
/* logging */
|
||||
if ((daemon->options & OPT_LOG_OPTS) && req_options)
|
||||
@@ -1476,12 +1549,12 @@ static void do_options(struct dhcp_context *context,
|
||||
for (i = 0; req_options[i] != OPTION_END; i++)
|
||||
{
|
||||
char *s = option_string(req_options[i]);
|
||||
q +=snprintf(q, MAXDNAME - (q - daemon->namebuff),
|
||||
"%d%s%s%s",
|
||||
req_options[i],
|
||||
s ? ":" : "",
|
||||
s ? s : "",
|
||||
req_options[i+1] == OPTION_END ? "" : ", ");
|
||||
q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
|
||||
"%d%s%s%s",
|
||||
req_options[i],
|
||||
s ? ":" : "",
|
||||
s ? s : "",
|
||||
req_options[i+1] == OPTION_END ? "" : ", ");
|
||||
if (req_options[i+1] == OPTION_END || (q - daemon->namebuff) > 40)
|
||||
{
|
||||
q = daemon->namebuff;
|
||||
@@ -1504,33 +1577,30 @@ static void do_options(struct dhcp_context *context,
|
||||
|
||||
/* See if we can send the boot stuff as options.
|
||||
To do this we need a requested option list, BOOTP
|
||||
and very old DHCP clients won't have this.
|
||||
and very old DHCP clients won't have this, we also
|
||||
provide an manual option to disable it.
|
||||
Some PXE ROMs have bugs (surprise!) and need zero-terminated
|
||||
names, so we always send those. */
|
||||
if (boot)
|
||||
{
|
||||
if (boot->sname)
|
||||
{
|
||||
if (req_options && in_list(req_options, OPTION_SNAME))
|
||||
{
|
||||
if (!(daemon->options & OPT_NO_OVERRIDE) &&
|
||||
req_options &&
|
||||
in_list(req_options, OPTION_SNAME))
|
||||
option_put_string(mess, end, OPTION_SNAME, boot->sname, 1);
|
||||
else
|
||||
{
|
||||
if (daemon->options & OPT_LOG_OPTS)
|
||||
my_syslog(LOG_INFO, _("server name: %s"), boot->sname);
|
||||
strncpy((char *)mess->sname, boot->sname, sizeof(mess->sname)-1);
|
||||
}
|
||||
strncpy((char *)mess->sname, boot->sname, sizeof(mess->sname)-1);
|
||||
}
|
||||
|
||||
if (boot->file)
|
||||
{
|
||||
if (req_options && in_list(req_options, OPTION_FILENAME))
|
||||
if (!(daemon->options & OPT_NO_OVERRIDE) &&
|
||||
req_options &&
|
||||
in_list(req_options, OPTION_FILENAME))
|
||||
option_put_string(mess, end, OPTION_FILENAME, boot->file, 1);
|
||||
else
|
||||
{
|
||||
if (daemon->options & OPT_LOG_OPTS)
|
||||
my_syslog(LOG_INFO, _("bootfile name: %s"), boot->file);
|
||||
strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
|
||||
}
|
||||
strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
|
||||
}
|
||||
|
||||
if (boot->next_server.s_addr)
|
||||
@@ -1539,12 +1609,39 @@ static void do_options(struct dhcp_context *context,
|
||||
if (daemon->options & OPT_LOG_OPTS)
|
||||
my_syslog(LOG_INFO, _("next server: %s"), inet_ntoa(mess->siaddr));
|
||||
}
|
||||
else
|
||||
/* Use the values of the relevant options if no dhcp-boot given and
|
||||
they're no explicitly asked for as options. */
|
||||
{
|
||||
if ((!req_options || !in_list(req_options, OPTION_FILENAME)) &&
|
||||
(opt = option_find2(netid, config_opts, OPTION_FILENAME)))
|
||||
{
|
||||
strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file)-1);
|
||||
done_file = 1;
|
||||
}
|
||||
|
||||
if ((!req_options || !in_list(req_options, OPTION_SNAME)) &&
|
||||
(opt = option_find2(netid, config_opts, OPTION_SNAME)))
|
||||
{
|
||||
strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname)-1);
|
||||
done_server = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (daemon->options & OPT_LOG_OPTS)
|
||||
{
|
||||
if (strlen((char *)mess->file) != 0)
|
||||
my_syslog(LOG_INFO, _("bootfile name: %s"), (char *)mess->file);
|
||||
|
||||
if (strlen((char *)mess->sname) != 0)
|
||||
my_syslog(LOG_INFO, _("server name: %s"), (char *)mess->sname);
|
||||
}
|
||||
|
||||
/* We don't want to do option-overload for BOOTP, so make the file and sname
|
||||
fields look like they are in use, even when they aren't. This gets restored
|
||||
at the end of this function. */
|
||||
|
||||
if (!req_options)
|
||||
if (!req_options || (daemon->options & OPT_NO_OVERRIDE))
|
||||
{
|
||||
f0 = mess->file[0];
|
||||
mess->file[0] = 1;
|
||||
@@ -1585,12 +1682,11 @@ static void do_options(struct dhcp_context *context,
|
||||
!option_find2(netid, config_opts, OPTION_DOMAINNAME))
|
||||
option_put_string(mess, end, OPTION_DOMAINNAME, daemon->domain_suffix, null_term);
|
||||
|
||||
/* Note that we ignore attempts to set the hostname using
|
||||
--dhcp-option=12,<name> and the fqdn using
|
||||
--dhc-option=81,<name> */
|
||||
/* Note that we ignore attempts to set the fqdn using --dhc-option=81,<name> */
|
||||
if (hostname)
|
||||
{
|
||||
if (in_list(req_options, OPTION_HOSTNAME))
|
||||
if (in_list(req_options, OPTION_HOSTNAME) &&
|
||||
!option_find2(netid, config_opts, OPTION_HOSTNAME))
|
||||
option_put_string(mess, end, OPTION_HOSTNAME, hostname, null_term);
|
||||
|
||||
if (fqdn_flags != 0)
|
||||
@@ -1636,41 +1732,54 @@ static void do_options(struct dhcp_context *context,
|
||||
|
||||
for (opt = config_opts; opt; opt = opt->next)
|
||||
{
|
||||
int optno = opt->opt;
|
||||
|
||||
/* was it asked for, or are we sending it anyway? */
|
||||
if (!(opt->flags & DHOPT_FORCE) && !in_list(req_options, opt->opt))
|
||||
if (!(opt->flags & DHOPT_FORCE) && !in_list(req_options, optno))
|
||||
continue;
|
||||
|
||||
/* prohibit some used-internally options */
|
||||
if (opt->opt == OPTION_HOSTNAME ||
|
||||
opt->opt == OPTION_CLIENT_FQDN ||
|
||||
opt->opt == OPTION_MAXMESSAGE ||
|
||||
opt->opt == OPTION_OVERLOAD ||
|
||||
opt->opt == OPTION_PAD ||
|
||||
opt->opt == OPTION_END)
|
||||
if (optno == OPTION_CLIENT_FQDN ||
|
||||
optno == OPTION_MAXMESSAGE ||
|
||||
optno == OPTION_OVERLOAD ||
|
||||
optno == OPTION_PAD ||
|
||||
optno == OPTION_END)
|
||||
continue;
|
||||
|
||||
if (optno == OPTION_SNAME && done_server)
|
||||
continue;
|
||||
|
||||
if (optno == OPTION_FILENAME && done_file)
|
||||
continue;
|
||||
|
||||
/* netids match and not encapsulated? */
|
||||
if (opt != option_find2(netid, config_opts, opt->opt))
|
||||
if (opt != option_find2(netid, config_opts, optno))
|
||||
continue;
|
||||
|
||||
/* For the options we have default values on
|
||||
dhc-option=<optionno> means "don't include this option"
|
||||
not "include a zero-length option" */
|
||||
if (opt->len == 0 &&
|
||||
(opt->opt == OPTION_NETMASK ||
|
||||
opt->opt == OPTION_BROADCAST ||
|
||||
opt->opt == OPTION_ROUTER ||
|
||||
opt->opt == OPTION_DNSSERVER))
|
||||
(optno == OPTION_NETMASK ||
|
||||
optno == OPTION_BROADCAST ||
|
||||
optno == OPTION_ROUTER ||
|
||||
optno == OPTION_DNSSERVER ||
|
||||
optno == OPTION_DOMAINNAME ||
|
||||
optno == OPTION_HOSTNAME))
|
||||
continue;
|
||||
|
||||
/* always force null-term for filename ans servername - buggy PXE again. */
|
||||
len = do_opt(opt, NULL, context->local,
|
||||
(optno == OPTION_SNAME || optno == OPTION_FILENAME) ? 1 : null_term);
|
||||
|
||||
len = do_opt(opt, NULL, context->local, null_term);
|
||||
if ((p = free_space(mess, end, opt->opt, len)))
|
||||
if ((p = free_space(mess, end, optno, len)))
|
||||
{
|
||||
do_opt(opt, p, context->local, null_term);
|
||||
|
||||
do_opt(opt, p, context->local,
|
||||
(optno == OPTION_SNAME || optno == OPTION_FILENAME) ? 1 : null_term);
|
||||
|
||||
/* If we send a vendor-id, revisit which vendor-ops we consider
|
||||
it appropriate to send. */
|
||||
if (opt->opt == OPTION_VENDOR_ID)
|
||||
if (optno == OPTION_VENDOR_ID)
|
||||
match_vendor_opts(p - 2, config_opts);
|
||||
}
|
||||
}
|
||||
@@ -1729,16 +1838,10 @@ static void do_options(struct dhcp_context *context,
|
||||
}
|
||||
|
||||
/* move agent_id back down to the end of the packet */
|
||||
if (agent_id)
|
||||
{
|
||||
p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
|
||||
memmove(p, agent_id, real_end - agent_id);
|
||||
p += real_end - agent_id;
|
||||
memset(p, 0, real_end - p); /* in case of overlap */
|
||||
}
|
||||
restore_agent_id(agent_id, mess, real_end);
|
||||
|
||||
/* restore BOOTP anti-overload hack */
|
||||
if (!req_options)
|
||||
if (!req_options || (daemon->options & OPT_NO_OVERRIDE))
|
||||
{
|
||||
mess->file[0] = f0;
|
||||
mess->sname[0] = s0;
|
||||
|
||||
112
src/tftp.c
112
src/tftp.c
@@ -2,12 +2,16 @@
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991.
|
||||
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
@@ -47,11 +51,17 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
int is_err = 1, if_index = 0;
|
||||
struct iname *tmp;
|
||||
struct tftp_transfer *transfer;
|
||||
|
||||
int port = daemon->start_tftp_port; /* may be zero to use ephemeral port */
|
||||
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
||||
int mtu = IP_PMTUDISC_DONT;
|
||||
#endif
|
||||
|
||||
union {
|
||||
struct cmsghdr align; /* this ensures alignment */
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
|
||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||
char control[CMSG_SPACE(sizeof(unsigned int))];
|
||||
#else
|
||||
char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
|
||||
#endif
|
||||
@@ -96,7 +106,11 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
|
||||
addr.sin_addr = *((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;
|
||||
#ifdef HAVE_SOLARIS_NETWORK
|
||||
if_index = *((unsigned int *)CMSG_DATA(cmptr));
|
||||
#else
|
||||
if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
|
||||
#endif
|
||||
|
||||
if (if_index == 0 || !if_indextoname(if_index, ifr.ifr_name))
|
||||
return;
|
||||
@@ -117,8 +131,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
|
||||
}
|
||||
|
||||
/* tell kernel to use ephemeral port */
|
||||
addr.sin_port = 0;
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_family = AF_INET;
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.sin_len = sizeof(addr);
|
||||
@@ -138,26 +151,48 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
transfer->backoff = 1;
|
||||
transfer->block = 1;
|
||||
transfer->blocksize = 512;
|
||||
transfer->offset = 0;
|
||||
transfer->file = NULL;
|
||||
transfer->opt_blocksize = transfer->opt_transize = 0;
|
||||
transfer->netascii = transfer->carrylf = 0;
|
||||
|
||||
if (bind(transfer->sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1 ||
|
||||
!fix_fd(transfer->sockfd))
|
||||
/* if we have a nailed-down range, iterate until we find a free one. */
|
||||
while (1)
|
||||
{
|
||||
free_transfer(transfer);
|
||||
return;
|
||||
if (bind(transfer->sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1 ||
|
||||
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
||||
setsockopt(transfer->sockfd, SOL_IP, IP_MTU_DISCOVER, &mtu, sizeof(mtu)) == -1 ||
|
||||
#endif
|
||||
!fix_fd(transfer->sockfd))
|
||||
{
|
||||
if (errno == EADDRINUSE && daemon->start_tftp_port != 0)
|
||||
{
|
||||
if (++port <= daemon->end_tftp_port)
|
||||
{
|
||||
addr.sin_port = htons(port);
|
||||
continue;
|
||||
}
|
||||
my_syslog(LOG_ERR, _("unable to get free port for TFTP"));
|
||||
}
|
||||
free_transfer(transfer);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
p = packet + 2;
|
||||
end = packet + len;
|
||||
|
||||
if (ntohs(*((unsigned short *)packet)) != OP_RRQ ||
|
||||
!(filename = next(&p, end)) ||
|
||||
!(mode = next(&p, end)) ||
|
||||
strcasecmp(mode, "octet") != 0)
|
||||
(strcasecmp(mode, "octet") != 0 && strcasecmp(mode, "netascii") != 0))
|
||||
len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), inet_ntoa(peer.sin_addr));
|
||||
else
|
||||
{
|
||||
if (strcasecmp(mode, "netascii") == 0)
|
||||
transfer->netascii = 1;
|
||||
|
||||
while ((opt = next(&p, end)))
|
||||
{
|
||||
if (strcasecmp(opt, "blksize") == 0 &&
|
||||
@@ -173,7 +208,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
transfer->block = 0;
|
||||
}
|
||||
|
||||
if (strcasecmp(opt, "tsize") == 0 && next(&p, end))
|
||||
if (strcasecmp(opt, "tsize") == 0 && next(&p, end) && !transfer->netascii)
|
||||
{
|
||||
transfer->opt_transize = 1;
|
||||
transfer->block = 0;
|
||||
@@ -348,7 +383,8 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
||||
/* Got ack, ensure we take the (re)transmit path */
|
||||
transfer->timeout = now;
|
||||
transfer->backoff = 0;
|
||||
transfer->block++;
|
||||
if (transfer->block++ != 0)
|
||||
transfer->offset += transfer->blocksize - transfer->expansion;
|
||||
}
|
||||
else if (ntohs(mess->op) == OP_ERR)
|
||||
{
|
||||
@@ -362,7 +398,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
||||
{
|
||||
char *q, *r;
|
||||
for (q = r = err; *r; r++)
|
||||
if (isprint(*r))
|
||||
if (isprint((int)*r))
|
||||
*(q++) = *r;
|
||||
*q = 0;
|
||||
}
|
||||
@@ -502,24 +538,52 @@ static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
|
||||
unsigned char data[];
|
||||
} *mess = (struct datamess *)packet;
|
||||
|
||||
off_t offset = transfer->blocksize * (transfer->block - 1);
|
||||
size_t size = transfer->file->size - offset;
|
||||
size_t size = transfer->file->size - transfer->offset;
|
||||
|
||||
if (offset > transfer->file->size)
|
||||
if (transfer->offset > transfer->file->size)
|
||||
return 0; /* finished */
|
||||
|
||||
if (size > transfer->blocksize)
|
||||
size = transfer->blocksize;
|
||||
|
||||
lseek(transfer->file->fd, offset, SEEK_SET);
|
||||
|
||||
mess->op = htons(OP_DATA);
|
||||
mess->block = htons((unsigned short)(transfer->block));
|
||||
|
||||
if (!read_write(transfer->file->fd, mess->data, size, 1))
|
||||
if (lseek(transfer->file->fd, transfer->offset, SEEK_SET) == (off_t)-1 ||
|
||||
!read_write(transfer->file->fd, mess->data, size, 1))
|
||||
return -1;
|
||||
else
|
||||
return size + 4;
|
||||
|
||||
transfer->expansion = 0;
|
||||
|
||||
/* Map '\n' to CR-LF in netascii mode */
|
||||
if (transfer->netascii)
|
||||
{
|
||||
size_t i;
|
||||
int newcarrylf;
|
||||
|
||||
for (i = 0, newcarrylf = 0; i < size; i++)
|
||||
if (mess->data[i] == '\n' && ( i != 0 || !transfer->carrylf))
|
||||
{
|
||||
if (size == transfer->blocksize)
|
||||
{
|
||||
transfer->expansion++;
|
||||
if (i == size - 1)
|
||||
newcarrylf = 1; /* don't expand LF again if it moves to the next block */
|
||||
}
|
||||
else
|
||||
size++; /* room in this block */
|
||||
|
||||
/* make space and insert CR */
|
||||
memmove(&mess->data[i+1], &mess->data[i], size - (i + 1));
|
||||
mess->data[i] = '\r';
|
||||
|
||||
i++;
|
||||
}
|
||||
transfer->carrylf = newcarrylf;
|
||||
|
||||
}
|
||||
|
||||
return size + 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
156
src/util.c
156
src/util.c
@@ -1,94 +1,103 @@
|
||||
/* dnsmasq is Copyright (c) 2000 - 2005 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991.
|
||||
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
/* Some code in this file contributed by Rob Funk. */
|
||||
|
||||
/* The SURF random number generator was taken from djbdns-1.05, by
|
||||
Daniel J Berstein, which is public domain. */
|
||||
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
#include <sys/times.h>
|
||||
#endif
|
||||
|
||||
/* Prefer arc4random(3) over random(3) over rand(3) */
|
||||
/* Also prefer /dev/urandom over /dev/random, to preserve the entropy pool */
|
||||
|
||||
#ifdef HAVE_ARC4RANDOM
|
||||
# define rand() arc4random()
|
||||
# define srand(s) (void)0
|
||||
# define RANDFILE (NULL)
|
||||
#else
|
||||
# ifdef HAVE_RANDOM
|
||||
# define rand() random()
|
||||
# define srand(s) srandom(s)
|
||||
# endif
|
||||
# ifdef HAVE_DEV_URANDOM
|
||||
# define RANDFILE "/dev/urandom"
|
||||
# else
|
||||
# ifdef HAVE_DEV_RANDOM
|
||||
# define RANDFILE "/dev/random"
|
||||
# else
|
||||
# define RANDFILE (NULL)
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
void rand_init(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned short rand16(void)
|
||||
{
|
||||
static int been_seeded = 0;
|
||||
const char *randfile = RANDFILE;
|
||||
|
||||
if (! been_seeded)
|
||||
{
|
||||
int fd, n = 0;
|
||||
unsigned int c = 0, seed = 0, badseed;
|
||||
char sbuf[sizeof(seed)];
|
||||
char *s;
|
||||
struct timeval now;
|
||||
|
||||
/* get the bad seed as a backup */
|
||||
/* (but we'd rather have something more random) */
|
||||
gettimeofday(&now, NULL);
|
||||
badseed = now.tv_sec ^ now.tv_usec ^ (getpid() << 16);
|
||||
|
||||
fd = open(randfile, O_RDONLY);
|
||||
if (fd < 0)
|
||||
seed = badseed;
|
||||
else
|
||||
{
|
||||
s = (char *) &seed;
|
||||
while ((c < sizeof(seed)) &&
|
||||
((n = read(fd, sbuf, sizeof(seed)) > 0)))
|
||||
{
|
||||
memcpy(s, sbuf, n);
|
||||
s += n;
|
||||
c += n;
|
||||
}
|
||||
if (n < 0)
|
||||
seed = badseed;
|
||||
close(fd);
|
||||
}
|
||||
|
||||
srand(seed);
|
||||
been_seeded = 1;
|
||||
}
|
||||
|
||||
/* Some rand() implementations have less randomness in low bits
|
||||
* than in high bits, so we only pay attention to the high ones.
|
||||
* But most implementations don't touch the high bit, so we
|
||||
* ignore that one.
|
||||
*/
|
||||
return( (unsigned short) (rand() >> 15) );
|
||||
return (unsigned short) (arc4random() >> 15);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* SURF random number generator */
|
||||
|
||||
typedef unsigned int uint32;
|
||||
|
||||
static uint32 seed[32];
|
||||
static uint32 in[12];
|
||||
static uint32 out[8];
|
||||
|
||||
void rand_init()
|
||||
{
|
||||
int fd = open(RANDFILE, O_RDONLY);
|
||||
|
||||
if (fd == -1 ||
|
||||
!read_write(fd, (unsigned char *)&seed, sizeof(seed), 1) ||
|
||||
!read_write(fd, (unsigned char *)&in, sizeof(in), 1))
|
||||
die(_("failed to seed the random number generator: %s"), NULL, EC_MISC);
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
#define ROTATE(x,b) (((x) << (b)) | ((x) >> (32 - (b))))
|
||||
#define MUSH(i,b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x,b));
|
||||
|
||||
static void surf(void)
|
||||
{
|
||||
uint32 t[12]; uint32 x; uint32 sum = 0;
|
||||
int r; int i; int loop;
|
||||
|
||||
for (i = 0;i < 12;++i) t[i] = in[i] ^ seed[12 + i];
|
||||
for (i = 0;i < 8;++i) out[i] = seed[24 + i];
|
||||
x = t[11];
|
||||
for (loop = 0;loop < 2;++loop) {
|
||||
for (r = 0;r < 16;++r) {
|
||||
sum += 0x9e3779b9;
|
||||
MUSH(0,5) MUSH(1,7) MUSH(2,9) MUSH(3,13)
|
||||
MUSH(4,5) MUSH(5,7) MUSH(6,9) MUSH(7,13)
|
||||
MUSH(8,5) MUSH(9,7) MUSH(10,9) MUSH(11,13)
|
||||
}
|
||||
for (i = 0;i < 8;++i) out[i] ^= t[i + 4];
|
||||
}
|
||||
}
|
||||
|
||||
unsigned short rand16(void)
|
||||
{
|
||||
static int outleft = 0;
|
||||
|
||||
if (!outleft) {
|
||||
if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
|
||||
surf();
|
||||
outleft = 8;
|
||||
}
|
||||
|
||||
return (unsigned short) out[--outleft];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
int legal_char(char c)
|
||||
{
|
||||
/* check for legal char a-z A-Z 0-9 -
|
||||
@@ -159,6 +168,14 @@ void *safe_malloc(size_t size)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void safe_pipe(int *fd, int read_noblock)
|
||||
{
|
||||
if (pipe(fd) == -1 ||
|
||||
!fix_fd(fd[1]) ||
|
||||
(read_noblock && !fix_fd(fd[0])))
|
||||
die(_("cannot create pipe: %s"), NULL, EC_MISC);
|
||||
}
|
||||
|
||||
void *whine_malloc(size_t size)
|
||||
{
|
||||
void *ret = malloc(size);
|
||||
@@ -344,7 +361,7 @@ int expand_buf(struct iovec *iov, size_t size)
|
||||
{
|
||||
void *new;
|
||||
|
||||
if (size <= iov->iov_len)
|
||||
if (size <= (size_t)iov->iov_len)
|
||||
return 1;
|
||||
|
||||
if (!(new = whine_malloc(size)))
|
||||
@@ -426,3 +443,4 @@ int read_write(int fd, unsigned char *packet, int size, int rw)
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user