1
0
mirror of https://github.com/infinet/dnsmasq.git synced 2025-05-08 00:56:06 +08:00

import of dnsmasq-2.41.tar.gz

This commit is contained in:
Simon Kelley 2008-02-12 20:43:05 +00:00
parent 5aabfc78bc
commit 824af85bdf
42 changed files with 8609 additions and 4729 deletions

125
CHANGELOG
View File

@ -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,126 @@ 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.

674
COPYING-v3 Normal file
View 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>.

22
FAQ
View File

@ -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?
@ -380,6 +379,14 @@ 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: 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 logs "running as root because setting capabilities failed"
when it starts up. Why did that happen and what can do to fix it?
@ -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.

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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
@ -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
@ -236,10 +244,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 +272,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 +303,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.
@ -381,7 +405,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 minutres. 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 +492,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 +577,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 +620,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
@ -598,6 +641,13 @@ 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
@ -677,7 +727,9 @@ 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.
variable DNSMASQ_OLD_HOSTNAME. DNSMASQ_INTERFACE stores the name of
the interface on which the reuest arrived; this is not set for "old"
actions when dnsmasq restarts.
All file decriptors are
closed except stdin, stdout and stderr which are open to /dev/null
(except in debug mode).
@ -768,12 +820,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 +863,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 +872,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 +884,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.

View File

@ -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.

1197
man/fr/dnsmasq.8 Normal file

File diff suppressed because it is too large Load Diff

1042
po/de.po

File diff suppressed because it is too large Load Diff

755
po/es.po

File diff suppressed because it is too large Load Diff

1032
po/fi.po

File diff suppressed because it is too large Load Diff

709
po/fr.po

File diff suppressed because it is too large Load Diff

722
po/id.po

File diff suppressed because it is too large Load Diff

1032
po/it.po

File diff suppressed because it is too large Load Diff

707
po/no.po

File diff suppressed because it is too large Load Diff

709
po/pl.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

708
po/ro.po

File diff suppressed because it is too large Load Diff

215
src/bpf.c
View File

@ -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 + IF_NAMESIZE;
#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;
@ -116,8 +219,10 @@ void send_via_bpf(struct dhcp_packet *mess, size_t len,
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

View File

@ -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"
@ -484,7 +488,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,14 +511,18 @@ 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 */
/* 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)
{
insert = up;
insert = up;
ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
up = &crecp->hash_next;
}
else
else if ((crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags)
{
*up = crecp->hash_next;
crecp->hash_next = *insert;
@ -827,14 +836,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 +856,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 +902,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;
@ -988,15 +1036,19 @@ 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)

View File

@ -2,15 +2,19 @@
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.41"
#define FTABSIZ 150 /* max number of outstanding requests (default) */
#define MAX_PROCS 20 /* max no children for TCP requests */
@ -35,6 +39,8 @@
#define RUNFILE "/var/run/dnsmasq.pid"
#if defined(__FreeBSD__) || defined (__OpenBSD__) || defined(__DragonFly__)
# define LEASEFILE "/var/db/dnsmasq.leases"
#elif defined(__sun__)
# define LEASEFILE "/var/cache/dnsmasq.leases"
#else
# define LEASEFILE "/var/lib/misc/dnsmasq.leases"
#endif
@ -91,10 +97,12 @@
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
@ -157,10 +165,9 @@ NOTES:
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
@ -243,7 +250,7 @@ typedef unsigned long in_addr_t;
#endif
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
#undef HAVE_LINUX_NETWORK
#define HAVE_BSD_NETWORK
/* Later verions of FreeBSD have getopt_long() */
#if defined(optional_argument) && defined(required_argument)
# define HAVE_GETOPT_LONG
@ -256,7 +263,7 @@ typedef unsigned long in_addr_t;
#define HAVE_SOCKADDR_SA_LEN
#elif defined(__APPLE__)
#undef HAVE_LINUX_NETWORK
#define HAVE_BSD_NETWORK
#undef HAVE_GETOPT_LONG
#define HAVE_ARC4RANDOM
#define HAVE_RANDOM
@ -268,15 +275,44 @@ 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
#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
#define HAVE_RANDOM
#undef HAVE_DEV_URANDOM
#undef HAVE_DEV_RANDOM
#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

View File

@ -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(stuct sockaddr_in6);
#endif
source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
addr.in6.sin6_port = htons(NAMESERVER_PORT);
@ -292,7 +296,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 +323,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;

View File

@ -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)
@ -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);
@ -278,7 +280,7 @@ void dhcp_packet(time_t now)
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(DHCP_CLIENT_PORT);
}
else
{
@ -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(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(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 then 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;

View File

@ -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"
@ -37,7 +41,7 @@ static char *compile_opts =
"no-"
#endif
"DBus "
#ifdef NO_GETTEXT
#ifndef LOCALEDIR
"no-"
#endif
"I18N "
@ -66,7 +70,7 @@ int main (int argc, char **argv)
struct passwd *ent_pw;
long i, max_fd = sysconf(_SC_OPEN_MAX);
#ifndef NO_GETTEXT
#ifdef LOCALEDIR
setlocale(LC_ALL, "");
bindtextdomain("dnsmasq", LOCALEDIR);
textdomain("dnsmasq");
@ -128,6 +132,11 @@ 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
now = dnsmasq_time();
if (daemon->dhcp)
@ -166,10 +175,12 @@ 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,31 +195,8 @@ 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)
{
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 (daemon->port != 0)
pre_allocate_sfds();
/* Use a pipe to carry signals and other events back to the event loop
in a race-free manner */
@ -247,8 +235,9 @@ int main (int argc, char **argv)
}
#endif
chdir("/");
if (chdir("/") != 0)
die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
/* write pidfile _after_ forking ! */
if (daemon->runfile && (pidfile = fopen(daemon->runfile, "w")))
{
@ -294,7 +283,7 @@ int main (int argc, char **argv)
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));
@ -308,8 +297,33 @@ int main (int argc, char **argv)
/* 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)
{
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)
{
/* finally drop root */
setuid(ent_pw->pw_uid);
@ -331,7 +345,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);
@ -356,7 +372,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 +426,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)
{
@ -429,8 +451,9 @@ int main (int argc, char **argv)
my_syslog(LOG_WARNING, _("running as root"));
}
check_servers();
if (daemon->port != 0)
check_servers();
pid = getpid();
while (1)
@ -517,7 +540,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 +564,7 @@ int main (int argc, char **argv)
}
check_dbus_listeners(&rset, &wset, &eset);
#endif
check_dns_listeners(&rset, now);
#ifdef HAVE_TFTP
@ -621,7 +644,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 +653,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:
@ -762,14 +786,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 +806,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,7 +820,8 @@ 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)
{
@ -805,7 +832,7 @@ static int set_dns_listeners(time_t now, fd_set *set, int *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 +840,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)
@ -845,7 +873,7 @@ static void check_dns_listeners(fd_set *set, time_t 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
@ -853,7 +881,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
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 +1025,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 +1100,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;

View File

@ -1,16 +1,20 @@
/* 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"
/* get these before config.h for IPv6 stuff... */
#include <sys/types.h>
@ -28,7 +32,7 @@
#include "config.h"
#define gettext_noop(S) (S)
#ifdef NO_GETTEXT
#ifndef LOCALEDIR
# define _(S) (S)
#else
# include <libintl.h>
@ -40,6 +44,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>
@ -58,7 +65,7 @@
#include <pwd.h>
#include <grp.h>
#include <stdarg.h>
#if defined(__OpenBSD__) || defined(__NetBSD__)
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__sun__)
# include <netinet/if_ether.h>
#else
# include <net/ethernet.h>
@ -74,15 +81,17 @@
# 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. */
extern int capset(cap_user_header_t header, cap_user_data_t data);
#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 */
@ -140,12 +149,15 @@ struct event_desc {
#define OPT_BOOTP_DYNAMIC (1<<20)
#define OPT_NO_PING (1<<21)
#define OPT_LEASE_RO (1<<22)
#define OPT_ALL_SERVERS (1<<23)
#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_NO_OVERRIDE (1<<30)
#define OPT_NO_REBIND (1<<31)
struct all_addr {
union {
@ -265,18 +277,22 @@ 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 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;
};
@ -354,6 +370,7 @@ struct dhcp_lease {
struct in_addr addr;
unsigned char *vendorclass, *userclass;
unsigned int vendorclass_len, userclass_len;
int last_interface;
struct dhcp_lease *next;
};
@ -406,6 +423,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 +437,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;
@ -522,7 +541,7 @@ extern struct daemon {
int max_logs; /* queue limit */
int cachesize, ftabsize;
int port, query_port;
unsigned long local_ttl;
unsigned long local_ttl, neg_ttl;
struct hostsfile *addn_hosts;
struct dhcp_context *dhcp;
struct dhcp_config *dhcp_conf;
@ -530,17 +549,20 @@ 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 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 serverfd *sfds;
struct irec *interfaces;
struct listener *listeners;
@ -573,7 +595,7 @@ extern struct daemon {
/* TFTP stuff */
struct tftp_transfer *tftp_trans;
char *tftp_prefix;
} *daemon;
/* cache.c */
@ -601,7 +623,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,
@ -649,7 +671,7 @@ 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);
@ -660,7 +682,8 @@ 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);
void pre_allocate_sfds(void);
int reload_servers(char *fname);
void check_servers(void);
int enumerate_interfaces();
@ -675,8 +698,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 +715,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 +730,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 +740,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 +757,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);

View File

@ -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"
@ -21,7 +25,7 @@ static struct frec *lookup_frec_by_sender(unsigned short id,
static unsigned short get_id(int force, unsigned short force_id, unsigned int crc);
/* 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 +144,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 +165,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 +175,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, 0, NULL, 0);
}
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 +221,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;
@ -311,6 +315,7 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
(struct all_addr *)&start->addr.in6.sin6_addr, 0,
NULL, 0);
#endif
start->queries++;
forwarded = 1;
forward->sentto = start;
if (!forward->forwardall)
@ -327,7 +332,7 @@ 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);
@ -341,7 +346,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 +404,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
@ -489,7 +498,8 @@ void reply_query(struct serverfd *sfd, time_t now)
break;
}
}
daemon->last_server = server;
if (!(daemon->options & OPT_ALL_SERVERS))
daemon->last_server = server;
}
/* If the answer is an error, keep the forward record in place in case
@ -531,6 +541,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 +611,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
@ -654,10 +671,16 @@ void receive_query(struct listener *listen, time_t now)
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,
@ -757,7 +780,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 +789,7 @@ unsigned char *tcp_request(int confd, time_t now,
if (last_server->tcpfd == -1)
continue;
c1 = size >> 8;
c2 = size;
@ -779,7 +803,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;

View File

@ -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,6 +44,7 @@ struct script_data
time_t expires;
#endif
unsigned char hwaddr[DHCP_CHADDR_MAX];
char interface[IF_NAMESIZE];
};
static struct script_data *buf = NULL;
@ -87,6 +94,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 +174,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 +191,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 +208,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 +227,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 +237,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 +323,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

View File

@ -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/>.
*/

View File

@ -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;

View File

@ -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"
@ -68,13 +72,6 @@ void log_start(struct passwd *ent_pw)
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);
/* if queuing is inhibited, make sure we allocate
the one required buffer now. */
if (max_logs == 0)
@ -83,29 +80,47 @@ 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)
my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"), daemon->log_file, strerror(errno));
}
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 +202,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 +249,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 +267,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 +298,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 +349,6 @@ void my_syslog(int priority, const char *format, ...)
log_write();
}
}
va_end(ap);
}
void set_log_writer(fd_set *set, int *maxfdp)

View File

@ -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"

View File

@ -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"
@ -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,51 @@ 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)
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;
/* 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 +490,68 @@ 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) &&
(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 +585,7 @@ 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)))
{
my_syslog(LOG_WARNING,
_("ignoring nameserver %s - cannot make/bind socket: %s"),
@ -525,6 +614,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 +717,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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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)
@ -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;

View File

@ -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"
@ -67,8 +71,7 @@
#define option_ptr(opt) ((void *)&(((unsigned char *)(opt))[2]))
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 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);
@ -95,7 +98,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 +107,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;
@ -153,7 +156,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;
}
}
@ -394,7 +397,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 +415,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)
@ -434,6 +434,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
if (hostname)
lease_set_hostname(lease, hostname, daemon->domain_suffix, 1);
lease_set_expires(lease, 0xffffffff, now); /* infinite lease */
lease_set_interface(lease, int_index);
clear_packet(mess, end);
do_options(context, mess, end, NULL,
@ -529,8 +530,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;
}
}
}
}
@ -573,6 +580,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;
@ -651,7 +667,7 @@ 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))
return 0;
@ -709,9 +725,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)
@ -722,7 +738,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name,
log_packet("DISCOVER", opt ? option_ptr(opt) : 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,7 +749,7 @@ 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);
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
clear_packet(mess, end);
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(context->local.s_addr));
@ -786,7 +802,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 +841,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 +850,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");
@ -929,7 +950,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,7 +966,8 @@ 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);
log_packet("ACK", &mess->yiaddr, emac, emac_len, iface_name, hostname);
clear_packet(mess, end);
@ -972,7 +994,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
@ -1004,7 +1026,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 +1074,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,17 +1086,6 @@ 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;
}
@ -1093,7 +1105,7 @@ static int sanitise(unsigned char *opt, char *buf)
for (i = option_len(opt); i > 0; i--)
{
char c = *p++;
if (isprint(c))
if (isprint((int)c))
*buf++ = c;
}
*buf = 0; /* add terminator */
@ -1236,6 +1248,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 +1283,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)
@ -1468,6 +1486,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 +1495,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 +1523,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 +1555,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 +1628,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 +1678,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);
}
}
@ -1738,7 +1793,7 @@ static void do_options(struct dhcp_context *context,
}
/* restore BOOTP anti-overload hack */
if (!req_options)
if (!req_options || (daemon->options & OPT_NO_OVERRIDE))
{
mess->file[0] = f0;
mess->sname[0] = s0;

View File

@ -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);
@ -141,13 +154,30 @@ void tftp_request(struct listener *listen, time_t now)
transfer->file = NULL;
transfer->opt_blocksize = transfer->opt_transize = 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;
@ -362,7 +392,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;
}

View File

@ -1,16 +1,19 @@
/* 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. */
#include "dnsmasq.h"
@ -344,7 +347,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)))