Importacion de la libdnsc.
commit
82fe2dd0c6
|
@ -0,0 +1,48 @@
|
||||||
|
# http://www.gnu.org/software/automake
|
||||||
|
Makefile.in
|
||||||
|
|
||||||
|
# http://www.gnu.org/software/autoconf
|
||||||
|
autom4te.cache
|
||||||
|
aclocal.m4
|
||||||
|
compile
|
||||||
|
configure
|
||||||
|
depcomp
|
||||||
|
install-sh
|
||||||
|
missing
|
||||||
|
|
||||||
|
build-aux/
|
||||||
|
|
||||||
|
config.h.in
|
||||||
|
config.h
|
||||||
|
Makefile
|
||||||
|
config.log
|
||||||
|
config.status
|
||||||
|
.deps
|
||||||
|
src/dns-c.pc
|
||||||
|
|
||||||
|
*.o
|
||||||
|
*.lo
|
||||||
|
*.la
|
||||||
|
src/.libs
|
||||||
|
stamp-h1
|
||||||
|
|
||||||
|
*~
|
||||||
|
|
||||||
|
m4
|
||||||
|
|
||||||
|
po/Makefile.in.in
|
||||||
|
po/Makevars.template
|
||||||
|
po/POTFILES
|
||||||
|
po/Rules-quot
|
||||||
|
po/boldquot.sed
|
||||||
|
po/en@boldquot.header
|
||||||
|
po/en@quot.header
|
||||||
|
po/insert-header.sin
|
||||||
|
po/quot.sed
|
||||||
|
po/remove-potcdate.sed
|
||||||
|
po/remove-potcdate.sin
|
||||||
|
po/stamp-po
|
||||||
|
|
||||||
|
*.gmo
|
||||||
|
*.mo
|
||||||
|
|
|
@ -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>.
|
|
@ -0,0 +1,368 @@
|
||||||
|
Installation Instructions
|
||||||
|
*************************
|
||||||
|
|
||||||
|
Copyright (C) 1994-1996, 1999-2002, 2004-2016 Free Software
|
||||||
|
Foundation, Inc.
|
||||||
|
|
||||||
|
Copying and distribution of this file, with or without modification,
|
||||||
|
are permitted in any medium without royalty provided the copyright
|
||||||
|
notice and this notice are preserved. This file is offered as-is,
|
||||||
|
without warranty of any kind.
|
||||||
|
|
||||||
|
Basic Installation
|
||||||
|
==================
|
||||||
|
|
||||||
|
Briefly, the shell command './configure && make && make install'
|
||||||
|
should configure, build, and install this package. The following
|
||||||
|
more-detailed instructions are generic; see the 'README' file for
|
||||||
|
instructions specific to this package. Some packages provide this
|
||||||
|
'INSTALL' file but do not implement all of the features documented
|
||||||
|
below. The lack of an optional feature in a given package is not
|
||||||
|
necessarily a bug. More recommendations for GNU packages can be found
|
||||||
|
in *note Makefile Conventions: (standards)Makefile Conventions.
|
||||||
|
|
||||||
|
The 'configure' shell script attempts to guess correct values for
|
||||||
|
various system-dependent variables used during compilation. It uses
|
||||||
|
those values to create a 'Makefile' in each directory of the package.
|
||||||
|
It may also create one or more '.h' files containing system-dependent
|
||||||
|
definitions. Finally, it creates a shell script 'config.status' that
|
||||||
|
you can run in the future to recreate the current configuration, and a
|
||||||
|
file 'config.log' containing compiler output (useful mainly for
|
||||||
|
debugging 'configure').
|
||||||
|
|
||||||
|
It can also use an optional file (typically called 'config.cache' and
|
||||||
|
enabled with '--cache-file=config.cache' or simply '-C') that saves the
|
||||||
|
results of its tests to speed up reconfiguring. Caching is disabled by
|
||||||
|
default to prevent problems with accidental use of stale cache files.
|
||||||
|
|
||||||
|
If you need to do unusual things to compile the package, please try
|
||||||
|
to figure out how 'configure' could check whether to do them, and mail
|
||||||
|
diffs or instructions to the address given in the 'README' so they can
|
||||||
|
be considered for the next release. If you are using the cache, and at
|
||||||
|
some point 'config.cache' contains results you don't want to keep, you
|
||||||
|
may remove or edit it.
|
||||||
|
|
||||||
|
The file 'configure.ac' (or 'configure.in') is used to create
|
||||||
|
'configure' by a program called 'autoconf'. You need 'configure.ac' if
|
||||||
|
you want to change it or regenerate 'configure' using a newer version of
|
||||||
|
'autoconf'.
|
||||||
|
|
||||||
|
The simplest way to compile this package is:
|
||||||
|
|
||||||
|
1. 'cd' to the directory containing the package's source code and type
|
||||||
|
'./configure' to configure the package for your system.
|
||||||
|
|
||||||
|
Running 'configure' might take a while. While running, it prints
|
||||||
|
some messages telling which features it is checking for.
|
||||||
|
|
||||||
|
2. Type 'make' to compile the package.
|
||||||
|
|
||||||
|
3. Optionally, type 'make check' to run any self-tests that come with
|
||||||
|
the package, generally using the just-built uninstalled binaries.
|
||||||
|
|
||||||
|
4. Type 'make install' to install the programs and any data files and
|
||||||
|
documentation. When installing into a prefix owned by root, it is
|
||||||
|
recommended that the package be configured and built as a regular
|
||||||
|
user, and only the 'make install' phase executed with root
|
||||||
|
privileges.
|
||||||
|
|
||||||
|
5. Optionally, type 'make installcheck' to repeat any self-tests, but
|
||||||
|
this time using the binaries in their final installed location.
|
||||||
|
This target does not install anything. Running this target as a
|
||||||
|
regular user, particularly if the prior 'make install' required
|
||||||
|
root privileges, verifies that the installation completed
|
||||||
|
correctly.
|
||||||
|
|
||||||
|
6. You can remove the program binaries and object files from the
|
||||||
|
source code directory by typing 'make clean'. To also remove the
|
||||||
|
files that 'configure' created (so you can compile the package for
|
||||||
|
a different kind of computer), type 'make distclean'. There is
|
||||||
|
also a 'make maintainer-clean' target, but that is intended mainly
|
||||||
|
for the package's developers. If you use it, you may have to get
|
||||||
|
all sorts of other programs in order to regenerate files that came
|
||||||
|
with the distribution.
|
||||||
|
|
||||||
|
7. Often, you can also type 'make uninstall' to remove the installed
|
||||||
|
files again. In practice, not all packages have tested that
|
||||||
|
uninstallation works correctly, even though it is required by the
|
||||||
|
GNU Coding Standards.
|
||||||
|
|
||||||
|
8. Some packages, particularly those that use Automake, provide 'make
|
||||||
|
distcheck', which can by used by developers to test that all other
|
||||||
|
targets like 'make install' and 'make uninstall' work correctly.
|
||||||
|
This target is generally not run by end users.
|
||||||
|
|
||||||
|
Compilers and Options
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Some systems require unusual options for compilation or linking that
|
||||||
|
the 'configure' script does not know about. Run './configure --help'
|
||||||
|
for details on some of the pertinent environment variables.
|
||||||
|
|
||||||
|
You can give 'configure' initial values for configuration parameters
|
||||||
|
by setting variables in the command line or in the environment. Here is
|
||||||
|
an example:
|
||||||
|
|
||||||
|
./configure CC=c99 CFLAGS=-g LIBS=-lposix
|
||||||
|
|
||||||
|
*Note Defining Variables::, for more details.
|
||||||
|
|
||||||
|
Compiling For Multiple Architectures
|
||||||
|
====================================
|
||||||
|
|
||||||
|
You can compile the package for more than one kind of computer at the
|
||||||
|
same time, by placing the object files for each architecture in their
|
||||||
|
own directory. To do this, you can use GNU 'make'. 'cd' to the
|
||||||
|
directory where you want the object files and executables to go and run
|
||||||
|
the 'configure' script. 'configure' automatically checks for the source
|
||||||
|
code in the directory that 'configure' is in and in '..'. This is known
|
||||||
|
as a "VPATH" build.
|
||||||
|
|
||||||
|
With a non-GNU 'make', it is safer to compile the package for one
|
||||||
|
architecture at a time in the source code directory. After you have
|
||||||
|
installed the package for one architecture, use 'make distclean' before
|
||||||
|
reconfiguring for another architecture.
|
||||||
|
|
||||||
|
On MacOS X 10.5 and later systems, you can create libraries and
|
||||||
|
executables that work on multiple system types--known as "fat" or
|
||||||
|
"universal" binaries--by specifying multiple '-arch' options to the
|
||||||
|
compiler but only a single '-arch' option to the preprocessor. Like
|
||||||
|
this:
|
||||||
|
|
||||||
|
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
|
||||||
|
CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
|
||||||
|
CPP="gcc -E" CXXCPP="g++ -E"
|
||||||
|
|
||||||
|
This is not guaranteed to produce working output in all cases, you
|
||||||
|
may have to build one architecture at a time and combine the results
|
||||||
|
using the 'lipo' tool if you have problems.
|
||||||
|
|
||||||
|
Installation Names
|
||||||
|
==================
|
||||||
|
|
||||||
|
By default, 'make install' installs the package's commands under
|
||||||
|
'/usr/local/bin', include files under '/usr/local/include', etc. You
|
||||||
|
can specify an installation prefix other than '/usr/local' by giving
|
||||||
|
'configure' the option '--prefix=PREFIX', where PREFIX must be an
|
||||||
|
absolute file name.
|
||||||
|
|
||||||
|
You can specify separate installation prefixes for
|
||||||
|
architecture-specific files and architecture-independent files. If you
|
||||||
|
pass the option '--exec-prefix=PREFIX' to 'configure', the package uses
|
||||||
|
PREFIX as the prefix for installing programs and libraries.
|
||||||
|
Documentation and other data files still use the regular prefix.
|
||||||
|
|
||||||
|
In addition, if you use an unusual directory layout you can give
|
||||||
|
options like '--bindir=DIR' to specify different values for particular
|
||||||
|
kinds of files. Run 'configure --help' for a list of the directories
|
||||||
|
you can set and what kinds of files go in them. In general, the default
|
||||||
|
for these options is expressed in terms of '${prefix}', so that
|
||||||
|
specifying just '--prefix' will affect all of the other directory
|
||||||
|
specifications that were not explicitly provided.
|
||||||
|
|
||||||
|
The most portable way to affect installation locations is to pass the
|
||||||
|
correct locations to 'configure'; however, many packages provide one or
|
||||||
|
both of the following shortcuts of passing variable assignments to the
|
||||||
|
'make install' command line to change installation locations without
|
||||||
|
having to reconfigure or recompile.
|
||||||
|
|
||||||
|
The first method involves providing an override variable for each
|
||||||
|
affected directory. For example, 'make install
|
||||||
|
prefix=/alternate/directory' will choose an alternate location for all
|
||||||
|
directory configuration variables that were expressed in terms of
|
||||||
|
'${prefix}'. Any directories that were specified during 'configure',
|
||||||
|
but not in terms of '${prefix}', must each be overridden at install time
|
||||||
|
for the entire installation to be relocated. The approach of makefile
|
||||||
|
variable overrides for each directory variable is required by the GNU
|
||||||
|
Coding Standards, and ideally causes no recompilation. However, some
|
||||||
|
platforms have known limitations with the semantics of shared libraries
|
||||||
|
that end up requiring recompilation when using this method, particularly
|
||||||
|
noticeable in packages that use GNU Libtool.
|
||||||
|
|
||||||
|
The second method involves providing the 'DESTDIR' variable. For
|
||||||
|
example, 'make install DESTDIR=/alternate/directory' will prepend
|
||||||
|
'/alternate/directory' before all installation names. The approach of
|
||||||
|
'DESTDIR' overrides is not required by the GNU Coding Standards, and
|
||||||
|
does not work on platforms that have drive letters. On the other hand,
|
||||||
|
it does better at avoiding recompilation issues, and works well even
|
||||||
|
when some directory options were not specified in terms of '${prefix}'
|
||||||
|
at 'configure' time.
|
||||||
|
|
||||||
|
Optional Features
|
||||||
|
=================
|
||||||
|
|
||||||
|
If the package supports it, you can cause programs to be installed
|
||||||
|
with an extra prefix or suffix on their names by giving 'configure' the
|
||||||
|
option '--program-prefix=PREFIX' or '--program-suffix=SUFFIX'.
|
||||||
|
|
||||||
|
Some packages pay attention to '--enable-FEATURE' options to
|
||||||
|
'configure', where FEATURE indicates an optional part of the package.
|
||||||
|
They may also pay attention to '--with-PACKAGE' options, where PACKAGE
|
||||||
|
is something like 'gnu-as' or 'x' (for the X Window System). The
|
||||||
|
'README' should mention any '--enable-' and '--with-' options that the
|
||||||
|
package recognizes.
|
||||||
|
|
||||||
|
For packages that use the X Window System, 'configure' can usually
|
||||||
|
find the X include and library files automatically, but if it doesn't,
|
||||||
|
you can use the 'configure' options '--x-includes=DIR' and
|
||||||
|
'--x-libraries=DIR' to specify their locations.
|
||||||
|
|
||||||
|
Some packages offer the ability to configure how verbose the
|
||||||
|
execution of 'make' will be. For these packages, running './configure
|
||||||
|
--enable-silent-rules' sets the default to minimal output, which can be
|
||||||
|
overridden with 'make V=1'; while running './configure
|
||||||
|
--disable-silent-rules' sets the default to verbose, which can be
|
||||||
|
overridden with 'make V=0'.
|
||||||
|
|
||||||
|
Particular systems
|
||||||
|
==================
|
||||||
|
|
||||||
|
On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC
|
||||||
|
is not installed, it is recommended to use the following options in
|
||||||
|
order to use an ANSI C compiler:
|
||||||
|
|
||||||
|
./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
|
||||||
|
|
||||||
|
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
|
||||||
|
|
||||||
|
HP-UX 'make' updates targets which have the same time stamps as their
|
||||||
|
prerequisites, which makes it generally unusable when shipped generated
|
||||||
|
files such as 'configure' are involved. Use GNU 'make' instead.
|
||||||
|
|
||||||
|
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
|
||||||
|
parse its '<wchar.h>' header file. The option '-nodtk' can be used as a
|
||||||
|
workaround. If GNU CC is not installed, it is therefore recommended to
|
||||||
|
try
|
||||||
|
|
||||||
|
./configure CC="cc"
|
||||||
|
|
||||||
|
and if that doesn't work, try
|
||||||
|
|
||||||
|
./configure CC="cc -nodtk"
|
||||||
|
|
||||||
|
On Solaris, don't put '/usr/ucb' early in your 'PATH'. This
|
||||||
|
directory contains several dysfunctional programs; working variants of
|
||||||
|
these programs are available in '/usr/bin'. So, if you need '/usr/ucb'
|
||||||
|
in your 'PATH', put it _after_ '/usr/bin'.
|
||||||
|
|
||||||
|
On Haiku, software installed for all users goes in '/boot/common',
|
||||||
|
not '/usr/local'. It is recommended to use the following options:
|
||||||
|
|
||||||
|
./configure --prefix=/boot/common
|
||||||
|
|
||||||
|
Specifying the System Type
|
||||||
|
==========================
|
||||||
|
|
||||||
|
There may be some features 'configure' cannot figure out
|
||||||
|
automatically, but needs to determine by the type of machine the package
|
||||||
|
will run on. Usually, assuming the package is built to be run on the
|
||||||
|
_same_ architectures, 'configure' can figure that out, but if it prints
|
||||||
|
a message saying it cannot guess the machine type, give it the
|
||||||
|
'--build=TYPE' option. TYPE can either be a short name for the system
|
||||||
|
type, such as 'sun4', or a canonical name which has the form:
|
||||||
|
|
||||||
|
CPU-COMPANY-SYSTEM
|
||||||
|
|
||||||
|
where SYSTEM can have one of these forms:
|
||||||
|
|
||||||
|
OS
|
||||||
|
KERNEL-OS
|
||||||
|
|
||||||
|
See the file 'config.sub' for the possible values of each field. If
|
||||||
|
'config.sub' isn't included in this package, then this package doesn't
|
||||||
|
need to know the machine type.
|
||||||
|
|
||||||
|
If you are _building_ compiler tools for cross-compiling, you should
|
||||||
|
use the option '--target=TYPE' to select the type of system they will
|
||||||
|
produce code for.
|
||||||
|
|
||||||
|
If you want to _use_ a cross compiler, that generates code for a
|
||||||
|
platform different from the build platform, you should specify the
|
||||||
|
"host" platform (i.e., that on which the generated programs will
|
||||||
|
eventually be run) with '--host=TYPE'.
|
||||||
|
|
||||||
|
Sharing Defaults
|
||||||
|
================
|
||||||
|
|
||||||
|
If you want to set default values for 'configure' scripts to share,
|
||||||
|
you can create a site shell script called 'config.site' that gives
|
||||||
|
default values for variables like 'CC', 'cache_file', and 'prefix'.
|
||||||
|
'configure' looks for 'PREFIX/share/config.site' if it exists, then
|
||||||
|
'PREFIX/etc/config.site' if it exists. Or, you can set the
|
||||||
|
'CONFIG_SITE' environment variable to the location of the site script.
|
||||||
|
A warning: not all 'configure' scripts look for a site script.
|
||||||
|
|
||||||
|
Defining Variables
|
||||||
|
==================
|
||||||
|
|
||||||
|
Variables not defined in a site shell script can be set in the
|
||||||
|
environment passed to 'configure'. However, some packages may run
|
||||||
|
configure again during the build, and the customized values of these
|
||||||
|
variables may be lost. In order to avoid this problem, you should set
|
||||||
|
them in the 'configure' command line, using 'VAR=value'. For example:
|
||||||
|
|
||||||
|
./configure CC=/usr/local2/bin/gcc
|
||||||
|
|
||||||
|
causes the specified 'gcc' to be used as the C compiler (unless it is
|
||||||
|
overridden in the site shell script).
|
||||||
|
|
||||||
|
Unfortunately, this technique does not work for 'CONFIG_SHELL' due to an
|
||||||
|
Autoconf limitation. Until the limitation is lifted, you can use this
|
||||||
|
workaround:
|
||||||
|
|
||||||
|
CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
|
||||||
|
|
||||||
|
'configure' Invocation
|
||||||
|
======================
|
||||||
|
|
||||||
|
'configure' recognizes the following options to control how it
|
||||||
|
operates.
|
||||||
|
|
||||||
|
'--help'
|
||||||
|
'-h'
|
||||||
|
Print a summary of all of the options to 'configure', and exit.
|
||||||
|
|
||||||
|
'--help=short'
|
||||||
|
'--help=recursive'
|
||||||
|
Print a summary of the options unique to this package's
|
||||||
|
'configure', and exit. The 'short' variant lists options used only
|
||||||
|
in the top level, while the 'recursive' variant lists options also
|
||||||
|
present in any nested packages.
|
||||||
|
|
||||||
|
'--version'
|
||||||
|
'-V'
|
||||||
|
Print the version of Autoconf used to generate the 'configure'
|
||||||
|
script, and exit.
|
||||||
|
|
||||||
|
'--cache-file=FILE'
|
||||||
|
Enable the cache: use and save the results of the tests in FILE,
|
||||||
|
traditionally 'config.cache'. FILE defaults to '/dev/null' to
|
||||||
|
disable caching.
|
||||||
|
|
||||||
|
'--config-cache'
|
||||||
|
'-C'
|
||||||
|
Alias for '--cache-file=config.cache'.
|
||||||
|
|
||||||
|
'--quiet'
|
||||||
|
'--silent'
|
||||||
|
'-q'
|
||||||
|
Do not print messages saying which checks are being made. To
|
||||||
|
suppress all normal output, redirect it to '/dev/null' (any error
|
||||||
|
messages will still be shown).
|
||||||
|
|
||||||
|
'--srcdir=DIR'
|
||||||
|
Look for the package's source code in directory DIR. Usually
|
||||||
|
'configure' can determine that directory automatically.
|
||||||
|
|
||||||
|
'--prefix=DIR'
|
||||||
|
Use DIR as the installation prefix. *note Installation Names:: for
|
||||||
|
more details, including other options available for fine-tuning the
|
||||||
|
installation locations.
|
||||||
|
|
||||||
|
'--no-create'
|
||||||
|
'-n'
|
||||||
|
Run the configure checks, but stop before creating any output
|
||||||
|
files.
|
||||||
|
|
||||||
|
'configure' also accepts some other, not widely useful, options. Run
|
||||||
|
'configure --help' for more details.
|
|
@ -0,0 +1,6 @@
|
||||||
|
SUBDIRS = src
|
||||||
|
|
||||||
|
#ACLOCAL_AMFLAGS = -I m4
|
||||||
|
|
||||||
|
#EXTRA_DIST = build-aux/config.rpath
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
AC_INIT([dns-c], [0.1.0], [], [dns_c])
|
||||||
|
|
||||||
|
AC_REVISION([Revision 1])
|
||||||
|
|
||||||
|
AC_CONFIG_AUX_DIR([build-aux])
|
||||||
|
|
||||||
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
|
# We need automake
|
||||||
|
AM_INIT_AUTOMAKE([-Wall -Werror])
|
||||||
|
|
||||||
|
AM_PROG_AR
|
||||||
|
|
||||||
|
AC_CONFIG_SRCDIR([src/dns2.c])
|
||||||
|
|
||||||
|
LT_INIT
|
||||||
|
|
||||||
|
# For debian systems, /usr as default
|
||||||
|
AC_PREFIX_DEFAULT([/usr])
|
||||||
|
|
||||||
|
# We need Gcc
|
||||||
|
AC_PROG_CC
|
||||||
|
# We need OBJC, for MAC
|
||||||
|
AC_PROG_OBJC
|
||||||
|
|
||||||
|
|
||||||
|
# Translate this program
|
||||||
|
#AM_GNU_GETTEXT_VERSION([0.19.3])
|
||||||
|
#AM_GNU_GETTEXT([external])
|
||||||
|
|
||||||
|
ALL_LINGUAS=""
|
||||||
|
AC_SUBST(ALL_LINGUAS)
|
||||||
|
|
||||||
|
AM_PROG_CC_C_O
|
||||||
|
|
||||||
|
# Revisar el host
|
||||||
|
AC_CANONICAL_HOST
|
||||||
|
|
||||||
|
case $host_os in
|
||||||
|
*mingw32* ) MINGW32=yes;;
|
||||||
|
* ) MINGW32=no;;
|
||||||
|
esac
|
||||||
|
case $host_os in
|
||||||
|
*cygwin* ) CYGWIN=yes;;
|
||||||
|
* ) CYGWIN=no;;
|
||||||
|
esac
|
||||||
|
case $host_os in
|
||||||
|
*linux* ) LINUX=yes;;
|
||||||
|
* ) LINUX=no;;
|
||||||
|
esac
|
||||||
|
case $host_os in
|
||||||
|
*darwin* ) MACOSX=yes;;
|
||||||
|
* ) MACOSX=no;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
AM_CONDITIONAL(MINGW32, test x$MINGW32 = xyes)
|
||||||
|
AM_CONDITIONAL(LINUX, test x$LINUX = xyes)
|
||||||
|
AM_CONDITIONAL(MACOSX, test x$MACOSX = xyes)
|
||||||
|
|
||||||
|
# Check for pkg-config
|
||||||
|
PKG_PROG_PKG_CONFIG
|
||||||
|
|
||||||
|
OPENSSL_VERSION=0.9.8
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([if you have openssl installed on your system])
|
||||||
|
PKG_CHECK_EXISTS([openssl >= $OPENSSL_VERSION], [AC_MSG_RESULT([yes])], [AC_MSG_FAILURE([openssl not found in your system])])
|
||||||
|
PKG_CHECK_MODULES(OPENSSL, [openssl >= $OPENSSL_VERSION], [], [])
|
||||||
|
|
||||||
|
AC_CONFIG_HEADERS([config.h])
|
||||||
|
|
||||||
|
AC_CONFIG_FILES([
|
||||||
|
Makefile
|
||||||
|
src/Makefile
|
||||||
|
src/dns-c.pc
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_OUTPUT
|
|
@ -0,0 +1,25 @@
|
||||||
|
# Automake file for dns-c
|
||||||
|
|
||||||
|
lib_LTLIBRARIES = libdnsc.la
|
||||||
|
|
||||||
|
libdnsc_la_SOURCES = dns2.c dns2.h dns2-private.h \
|
||||||
|
glist.c glist.h \
|
||||||
|
header.c header.h \
|
||||||
|
packet.c packet.h \
|
||||||
|
question.c question.h \
|
||||||
|
rr.c rr.h \
|
||||||
|
utils.c utils.h \
|
||||||
|
resolver.c updater.c \
|
||||||
|
constants.h
|
||||||
|
|
||||||
|
libdnsc_la_CFLAGS = $(OPENSSL_CFLAGS)
|
||||||
|
libdnsc_la_LDFLAGS = $(OPENSSL_LIBS) -version-info 0:1:0 -no-undefined -export-symbols $(srcdir)/libdnsc.sym
|
||||||
|
libdnsc_la_DEPENDENCIES = libdnsc.sym
|
||||||
|
libdnscdir = $(includedir)/libdns_c/dns_c
|
||||||
|
libdnsc_HEADERS = dns2.h rr.h constants.h
|
||||||
|
|
||||||
|
pkgconfigdir = $(libdir)/pkgconfig
|
||||||
|
dist_pkgconfig_DATA = dns-c.pc
|
||||||
|
|
||||||
|
EXTRA_DIST = libdnsc.sym
|
||||||
|
|
|
@ -0,0 +1,305 @@
|
||||||
|
#ifndef __CONSTANTS_H__
|
||||||
|
#define __CONSTANTS_H__
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define DNS_HEADER_SIZE 12
|
||||||
|
|
||||||
|
/*
|
||||||
|
* max size of a UDP packet
|
||||||
|
*/
|
||||||
|
#define DNS_MAX_UDP_SIZE 512
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Query/Response flag
|
||||||
|
*/
|
||||||
|
// RFC 1035
|
||||||
|
#define QR_QUERY 0
|
||||||
|
// RFC 1035
|
||||||
|
#define QR_RESPONSE 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DNS Op Codes
|
||||||
|
*/
|
||||||
|
// RFC 1035
|
||||||
|
#define OPCODE_QUERY 0
|
||||||
|
// RFC 1035, RFC 3425
|
||||||
|
#define OPCODE_IQUERY 1
|
||||||
|
// RFC 1035
|
||||||
|
#define OPCODE_STATUS 2
|
||||||
|
// RFC 1996
|
||||||
|
#define OPCODE_NOTIFY 4
|
||||||
|
// RFC 2136
|
||||||
|
#define OPCODE_UPDATE 5
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Resource Record Classes
|
||||||
|
*/
|
||||||
|
// RFC 1035
|
||||||
|
#define RR_CLASS_IN 1
|
||||||
|
// RFC 1035
|
||||||
|
#define RR_CLASS_CH 3
|
||||||
|
// RFC 1035
|
||||||
|
#define RR_CLASS_HS 4
|
||||||
|
// RFC 2136
|
||||||
|
#define RR_CLASS_NONE 254
|
||||||
|
// RFC 1035
|
||||||
|
#define RR_CLASS_ANY 255
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DNS Response Codes
|
||||||
|
*/
|
||||||
|
// RFC 1035
|
||||||
|
#define RCODE_NOERROR 0
|
||||||
|
// RFC 1035
|
||||||
|
#define RCODE_FORMERR 1
|
||||||
|
// RFC 1035
|
||||||
|
#define RCODE_SERVFAIL 2
|
||||||
|
// RFC 1035
|
||||||
|
#define RCODE_NXDOMAIN 3
|
||||||
|
// RFC 1035
|
||||||
|
#define RCODE_NOTIMP 4
|
||||||
|
// RFC 1035
|
||||||
|
#define RCODE_REFUSED 5
|
||||||
|
// RFC 2136
|
||||||
|
#define RCODE_YXDOMAIN 6
|
||||||
|
// RFC 2136
|
||||||
|
#define RCODE_YXRRSET 7
|
||||||
|
// RFC 2136
|
||||||
|
#define RCODE_NXRRSET 8
|
||||||
|
// RFC 2136
|
||||||
|
#define RCODE_NOTAUTH 9
|
||||||
|
// RFC 2136
|
||||||
|
#define RCODE_NOTZONE 10
|
||||||
|
|
||||||
|
// 11-15 reserved
|
||||||
|
|
||||||
|
// RFC 2845
|
||||||
|
#define RCODE_BADSIG 16
|
||||||
|
// RFC 6891
|
||||||
|
#define RCODE_BADVERS 16
|
||||||
|
// RFC 2845
|
||||||
|
#define RCODE_BADKEY 17
|
||||||
|
// RFC 2845
|
||||||
|
#define RCODE_BADTIME 18
|
||||||
|
// RFC 2930
|
||||||
|
#define RCODE_BADMODE 19
|
||||||
|
// RFC 2930
|
||||||
|
#define RCODE_BADNAME 20
|
||||||
|
// RFC 2930
|
||||||
|
#define RCODE_BADALG 21
|
||||||
|
// RFC 4635
|
||||||
|
#define RCODE_BADTRUNC 22
|
||||||
|
// RFC 7873
|
||||||
|
#define RCODE_BADCOOKIE 23
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DNS RR TYPES
|
||||||
|
*/
|
||||||
|
|
||||||
|
// RFC 2931 pseudo type
|
||||||
|
#define RR_TYPE_SIG0 0
|
||||||
|
// RFC 1035
|
||||||
|
#define RR_TYPE_A 1
|
||||||
|
// RFC 1035
|
||||||
|
#define RR_TYPE_NS 2
|
||||||
|
// RFC 1035 - obsolete, Not implemented
|
||||||
|
#define RR_TYPE_MD 3
|
||||||
|
// RFC 1035 - obsolete, Not implemented
|
||||||
|
#define RR_TYPE_MF 4
|
||||||
|
// RFC 1035
|
||||||
|
#define RR_TYPE_CNAME 5
|
||||||
|
// RFC 1035
|
||||||
|
#define RR_TYPE_SOA 6
|
||||||
|
// RFC 1035 - obsolete, Not implemented
|
||||||
|
#define RR_TYPE_MB 7
|
||||||
|
// RFC 1035 - obsolete, Not implemented
|
||||||
|
#define RR_TYPE_MG 8
|
||||||
|
// RFC 1035 - obsolete, Not implemented
|
||||||
|
#define RR_TYPE_MR 9
|
||||||
|
// RFC 1035 - obsolete, Not implemented
|
||||||
|
#define RR_TYPE_NULL 10
|
||||||
|
// RFC 1035
|
||||||
|
#define RR_TYPE_WKS 11
|
||||||
|
// RFC 1035
|
||||||
|
#define RR_TYPE_PTR 12
|
||||||
|
// RFC 1035
|
||||||
|
#define RR_TYPE_HINFO 13
|
||||||
|
// RFC 1035 - obsolete, Not implemented
|
||||||
|
#define RR_TYPE_MINFO 14
|
||||||
|
// RFC 1035
|
||||||
|
#define RR_TYPE_MX 15
|
||||||
|
// RFC 1035
|
||||||
|
#define RR_TYPE_TXT 16
|
||||||
|
// RFC 1183
|
||||||
|
#define RR_TYPE_RP 17
|
||||||
|
// RFC 1183
|
||||||
|
#define RR_TYPE_AFSDB 18
|
||||||
|
// RFC 1183
|
||||||
|
#define RR_TYPE_X25 19
|
||||||
|
// RFC 1183
|
||||||
|
#define RR_TYPE_ISDN 20
|
||||||
|
// RFC 1183
|
||||||
|
#define RR_TYPE_RT 21
|
||||||
|
// RFC 1706
|
||||||
|
#define RR_TYPE_NSAP 22
|
||||||
|
// RFC 1348 - obsolete, Not implemented
|
||||||
|
#define RR_TYPE_NSAP_PTR 23
|
||||||
|
// RFC 2535
|
||||||
|
#define RR_TYPE_SIG 24
|
||||||
|
// RFC 2535, RFC 2930
|
||||||
|
#define RR_TYPE_KEY 25
|
||||||
|
// RFC 2163
|
||||||
|
#define RR_TYPE_PX 26
|
||||||
|
// RFC 1712 - Not implemented
|
||||||
|
#define RR_TYPE_GPOS 27
|
||||||
|
// RFC 3596
|
||||||
|
#define RR_TYPE_AAAA 28
|
||||||
|
// RFC 1876
|
||||||
|
#define RR_TYPE_LOC 29
|
||||||
|
// RFC 2065, obsoleted by by RFC 3755
|
||||||
|
#define RR_TYPE_NXT 30
|
||||||
|
// [Patton][Patton1995]
|
||||||
|
#define RR_TYPE_EID 31
|
||||||
|
// [Patton][Patton1995]
|
||||||
|
#define RR_TYPE_NIMLOC 32
|
||||||
|
// RFC 2782
|
||||||
|
#define RR_TYPE_SRV 33
|
||||||
|
// Windows only
|
||||||
|
#define RR_TYPE_ATMA 34
|
||||||
|
// RFC 2915
|
||||||
|
#define RR_TYPE_NAPTR 35
|
||||||
|
// RFC 2230
|
||||||
|
#define RR_TYPE_KX 36
|
||||||
|
// RFC 4398
|
||||||
|
#define RR_TYPE_CERT 37
|
||||||
|
// downgraded to experimental by RFC 3363
|
||||||
|
#define RR_TYPE_A6 38
|
||||||
|
// RFC 2672
|
||||||
|
#define RR_TYPE_DNAME 39
|
||||||
|
// Not implemented
|
||||||
|
#define RR_TYPE_SINK 40
|
||||||
|
// RFC 2671
|
||||||
|
#define RR_TYPE_OPT 41
|
||||||
|
// RFC 3123
|
||||||
|
#define RR_TYPE_APL 42
|
||||||
|
// RFC 4034
|
||||||
|
#define RR_TYPE_DS 43
|
||||||
|
// RFC 4255
|
||||||
|
#define RR_TYPE_SSHFP 44
|
||||||
|
// RFC 4025
|
||||||
|
#define RR_TYPE_IPSECKEY 45
|
||||||
|
// RFC 4034
|
||||||
|
#define RR_TYPE_RRSIG 46
|
||||||
|
// RFC 4034
|
||||||
|
#define RR_TYPE_NSEC 47
|
||||||
|
// RFC 4034
|
||||||
|
#define RR_TYPE_DNSKEY 48
|
||||||
|
// RFC 4701
|
||||||
|
#define RR_TYPE_DHCID 49
|
||||||
|
// RFC 5155
|
||||||
|
#define RR_TYPE_NSEC3 50
|
||||||
|
// RFC 5155
|
||||||
|
#define RR_TYPE_NSEC3PARAM 51
|
||||||
|
// RFC 6698
|
||||||
|
#define RR_TYPE_TLSA 52
|
||||||
|
// draft-ietf-dane-smime-10
|
||||||
|
#define RR_TYPE_SMIMEA 53
|
||||||
|
|
||||||
|
// 54 unassigned
|
||||||
|
|
||||||
|
// RFC 5205
|
||||||
|
#define RR_TYPE_HIP 55
|
||||||
|
// Not implemented
|
||||||
|
#define RR_TYPE_NINFO 56
|
||||||
|
// Not implemented
|
||||||
|
#define RR_TYPE_RKEY 57
|
||||||
|
//
|
||||||
|
#define RR_TYPE_TALINK 58
|
||||||
|
// RFC 7344
|
||||||
|
#define RR_TYPE_CDS 59
|
||||||
|
// RFC 7344
|
||||||
|
#define RR_TYPE_CDNSKEY 60
|
||||||
|
// RFC 7929
|
||||||
|
#define RR_TYPE_OPENPGPKEY 61
|
||||||
|
// RFC 7477
|
||||||
|
#define RR_TYPE_CSYNC 62
|
||||||
|
|
||||||
|
// 63 - 98 unassigned
|
||||||
|
|
||||||
|
// RFC 4408
|
||||||
|
#define RR_TYPE_SPF 99
|
||||||
|
// no RFC, Not implemented
|
||||||
|
#define RR_TYPE_UINFO 100
|
||||||
|
// no RFC, Not implemented
|
||||||
|
#define RR_TYPE_UID 101
|
||||||
|
// no RFC, Not implemented
|
||||||
|
#define RR_TYPE_GID 102
|
||||||
|
// no RFC, Not implemented
|
||||||
|
#define RR_TYPE_UNSPEC 103
|
||||||
|
// RFC 6742
|
||||||
|
#define RR_TYPE_NID 104
|
||||||
|
// RFC 6742
|
||||||
|
#define RR_TYPE_L32 105
|
||||||
|
// RFC 6742
|
||||||
|
#define RR_TYPE_L64 106
|
||||||
|
// RFC 6742
|
||||||
|
#define RR_TYPE_LP 107
|
||||||
|
// RFC 7043
|
||||||
|
#define RR_TYPE_EUI48 108
|
||||||
|
// RFC 7043
|
||||||
|
#define RR_TYPE_EUI64 109
|
||||||
|
|
||||||
|
// 110 - 248 unassigned
|
||||||
|
|
||||||
|
// RFC 2930
|
||||||
|
#define RR_TYPE_TKEY 249
|
||||||
|
// RFC 2845
|
||||||
|
#define RR_TYPE_TSIG 250
|
||||||
|
// RFC 1995 - only a full (AXFR) is supported
|
||||||
|
#define RR_TYPE_IXFR 251
|
||||||
|
// RFC 1035
|
||||||
|
#define RR_TYPE_AXFR 252
|
||||||
|
// RFC 883, Not implemented
|
||||||
|
#define RR_TYPE_MAILB 253
|
||||||
|
// RFC 973, Not implemented
|
||||||
|
#define RR_TYPE_MAILA 254
|
||||||
|
// RFC 1035 - we support both 'ANY' and '*'
|
||||||
|
#define RR_TYPE_ANY 255
|
||||||
|
// tools.ietf.org/html/draft-faltstrom-uri-06
|
||||||
|
#define RR_TYPE_URI 256
|
||||||
|
// tools.ietf.org/html/draft-ietf-pkix-caa-03
|
||||||
|
#define RR_TYPE_CAA 257
|
||||||
|
// Application Visibility and Control
|
||||||
|
#define RR_TYPE_AVC 258
|
||||||
|
|
||||||
|
// 259 - 32767 unassigned
|
||||||
|
|
||||||
|
// same as DS
|
||||||
|
#define RR_TYPE_TA 32768
|
||||||
|
// RFC 4431
|
||||||
|
#define RR_TYPE_DLV 32769
|
||||||
|
// Private Bind record
|
||||||
|
#define RR_TYPE_TYPE65534 65534
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TSIG TYPES
|
||||||
|
*/
|
||||||
|
|
||||||
|
// RFC 2845, required
|
||||||
|
#define RR_TSIG_HMAC_MD5 "hmac-md5.sig-alg.reg.int"
|
||||||
|
// unsupported, optional
|
||||||
|
#define RR_TSIG_GSS_TSIG "gss-tsig"
|
||||||
|
// RFC 4635, required
|
||||||
|
#define RR_TSIG_HMAC_SHA1 "hmac-sha1"
|
||||||
|
// RFC 4635, optional
|
||||||
|
#define RR_TSIG_HMAC_SHA224 "hmac-sha224"
|
||||||
|
// RFC 4635, required
|
||||||
|
#define RR_TSIG_HMAC_SHA256 "hmac-sha256"
|
||||||
|
// RFC 4635, optional
|
||||||
|
#define RR_TSIG_HMAC_SHA384 "hmac-sha384"
|
||||||
|
// RFC 4635, optional
|
||||||
|
#define RR_TSIG_HMAC_SHA512 "hmac-sha512"
|
||||||
|
|
||||||
|
#endif /* __CONSTANTS_H__ */
|
|
@ -0,0 +1,11 @@
|
||||||
|
prefix=@prefix@
|
||||||
|
exec_prefix=@exec_prefix@
|
||||||
|
libdir=@libdir@
|
||||||
|
includedir=@includedir@
|
||||||
|
|
||||||
|
Name: DNS-C Library
|
||||||
|
Description: Client Library for doing DNS queries or updates
|
||||||
|
Version: @VERSION@
|
||||||
|
Libs: -L${libdir} -ldnsc
|
||||||
|
Requires.private: openssl >= 0.9.8
|
||||||
|
Cflags: -I${includedir}/libdns_c
|
|
@ -0,0 +1,50 @@
|
||||||
|
#ifndef __DNS2_PRIVATE_H__
|
||||||
|
#define __DNS2_PRIVATE_H__
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "packet.h"
|
||||||
|
#include "glist.h"
|
||||||
|
#include "rr.h"
|
||||||
|
#include "dns2.h"
|
||||||
|
|
||||||
|
struct _DNS2 {
|
||||||
|
int type;
|
||||||
|
int timeout;
|
||||||
|
|
||||||
|
/* Lista nameservers a los cuáles mandar la petición */
|
||||||
|
GList *nameservers;
|
||||||
|
|
||||||
|
/* Se utiliza para las actualizaciones de zona */
|
||||||
|
char *zone;
|
||||||
|
|
||||||
|
DNSPacket *packet;
|
||||||
|
|
||||||
|
/* Para la recepción de datos */
|
||||||
|
unsigned char buffer_read[8192];
|
||||||
|
int buffer_read_pos;
|
||||||
|
|
||||||
|
DNSPacket *packet_response;
|
||||||
|
int force_use_tcp;
|
||||||
|
|
||||||
|
/* Usado para saber si quiere recursión en las consultas */
|
||||||
|
int want_recursion;
|
||||||
|
|
||||||
|
DNSRR *auth_signature;
|
||||||
|
|
||||||
|
/* Para el envio de red */
|
||||||
|
int state;
|
||||||
|
int direction;
|
||||||
|
int retry_count;
|
||||||
|
struct timespec last_time_sent;
|
||||||
|
|
||||||
|
GList *current_ns;
|
||||||
|
};
|
||||||
|
|
||||||
|
DNS2 *dns2_new (void);
|
||||||
|
|
||||||
|
#endif /* __DNS2_PRIVATE_H__ */
|
||||||
|
|
|
@ -0,0 +1,774 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include <sys/poll.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
#include "dns2.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "packet.h"
|
||||||
|
#include "constants.h"
|
||||||
|
#include "glist.h"
|
||||||
|
#include "rr.h"
|
||||||
|
#include "question.h"
|
||||||
|
|
||||||
|
#include "dns2-private.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char name[512];
|
||||||
|
|
||||||
|
struct sockaddr_storage server_addr;
|
||||||
|
socklen_t addr_size;
|
||||||
|
|
||||||
|
int socket;
|
||||||
|
} NameServer;
|
||||||
|
|
||||||
|
|
||||||
|
/* Prototipos de función */
|
||||||
|
int _dns2_internal_tcp_start_connect (DNS2 *obj);
|
||||||
|
int _dns2_internal_udp_create (DNS2 *obj);
|
||||||
|
|
||||||
|
int _dns2_internal_tcp_connect_continue (DNS2 *obj);
|
||||||
|
int _dns2_internal_udp_send (DNS2 *obj);
|
||||||
|
int _dns2_internal_tcp_send (DNS2 *obj);
|
||||||
|
int _dns2_internal_udp_recv (DNS2 *obj);
|
||||||
|
int _dns2_internal_tcp_recv (DNS2 *obj);
|
||||||
|
int _dns2_internal_tcp_next_or_error (DNS2 *obj);
|
||||||
|
void dns2_clean_network (DNS2 *obj);
|
||||||
|
|
||||||
|
double _dns2_diff_timespec (const struct timespec *time1, const struct timespec *time0) {
|
||||||
|
return (time1->tv_sec - time0->tv_sec)
|
||||||
|
+ (time1->tv_nsec - time0->tv_nsec) / 1000000000.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dns2_async (DNS2 *obj) {
|
||||||
|
int length;
|
||||||
|
// checkServers
|
||||||
|
DNSRR *signature;
|
||||||
|
DNSQuestion *question;
|
||||||
|
int max_udp_size;
|
||||||
|
|
||||||
|
if (obj->state != DNS_STATE_FREE) {
|
||||||
|
return DNS_COMMAND_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj->packet == NULL) {
|
||||||
|
return DNS_COMMAND_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resetear el estado del paquete */
|
||||||
|
dns_packet_reset (obj->packet);
|
||||||
|
|
||||||
|
obj->current_ns = g_list_first (obj->nameservers);
|
||||||
|
obj->retry_count = 0;
|
||||||
|
if (obj->current_ns == NULL) {
|
||||||
|
return DNS_COMMAND_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Actualizar el contador de paquetes */
|
||||||
|
dns_packet_recount_items (obj->packet);
|
||||||
|
|
||||||
|
if (obj->type == DNS_UPDATER && (obj->packet->header.qdcount == 0 || obj->packet->header.nscount == 0)) {
|
||||||
|
|
||||||
|
/* Error, nada que mandar en el update */
|
||||||
|
return DNS_COMMAND_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
max_udp_size = DNS_MAX_UDP_SIZE;
|
||||||
|
|
||||||
|
/* Si tiene una firma, generar la firma */
|
||||||
|
if (obj->auth_signature != NULL) {
|
||||||
|
if (obj->auth_signature->type == RR_TYPE_TSIG /*||
|
||||||
|
obj->auth_signature->tipo == RR_TYPE_SIG*/) {
|
||||||
|
|
||||||
|
signature = dns2_rr_dup (obj->auth_signature);
|
||||||
|
dns_rr_pack_generate_signature (signature, obj->packet);
|
||||||
|
obj->packet->additional = g_list_append (obj->packet->additional, signature);
|
||||||
|
obj->packet->header.arcount = g_list_length (obj->packet->additional);
|
||||||
|
}
|
||||||
|
max_udp_size = 4000;
|
||||||
|
}
|
||||||
|
|
||||||
|
dns_packet_pack_data (obj->packet);
|
||||||
|
|
||||||
|
/* ------ Para depuración ------
|
||||||
|
unsigned char *data;
|
||||||
|
|
||||||
|
length = dns_packet_get_data (obj->packet, &data);
|
||||||
|
for (int g = 0; g<length; g++) {
|
||||||
|
printf ("%02x", (unsigned int) data[g]);
|
||||||
|
}
|
||||||
|
printf ("\nEnd data.\n");
|
||||||
|
------ FIN de la depuración ------ */
|
||||||
|
|
||||||
|
/* Revisar el tipo de pregunta, algunos tipos de pregunta, como los ANY requieren TCP */
|
||||||
|
question = (DNSQuestion *) obj->packet->questions->data;
|
||||||
|
|
||||||
|
if (question->qtype == RR_TYPE_ANY || question->qtype == RR_TYPE_AXFR) {
|
||||||
|
obj->force_use_tcp = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
length = dns_packet_get_data (obj->packet, NULL);
|
||||||
|
if (length > max_udp_size || obj->force_use_tcp == 1) {
|
||||||
|
obj->state = DNS_STATE_TCP_CONNECT;
|
||||||
|
|
||||||
|
return _dns2_internal_tcp_start_connect (obj);
|
||||||
|
} else {
|
||||||
|
obj->state = DNS_STATE_UDP;
|
||||||
|
|
||||||
|
return _dns2_internal_udp_create (obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int dns2_async_continue (DNS2 *obj, int happen) {
|
||||||
|
if (obj->state == DNS_STATE_FREE) {
|
||||||
|
return DNS_COMMAND_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj->direction == DNS_POLL_WANT_READ) {
|
||||||
|
if ((happen & DNS_POLL_WANT_READ) == 0) {
|
||||||
|
return DNS_COMMAND_POLL;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (obj->state) {
|
||||||
|
case DNS_STATE_UDP:
|
||||||
|
return _dns2_internal_udp_recv (obj);
|
||||||
|
case DNS_STATE_TCP:
|
||||||
|
return _dns2_internal_tcp_recv (obj);
|
||||||
|
}
|
||||||
|
} else if (obj->direction == DNS_POLL_WANT_WRITE) {
|
||||||
|
if ((happen & DNS_POLL_WANT_WRITE) == 0) {
|
||||||
|
return DNS_COMMAND_POLL;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (obj->state) {
|
||||||
|
case DNS_STATE_TCP_CONNECT:
|
||||||
|
return _dns2_internal_tcp_connect_continue (obj);
|
||||||
|
case DNS_STATE_UDP:
|
||||||
|
return _dns2_internal_udp_send (obj);
|
||||||
|
case DNS_STATE_TCP:
|
||||||
|
return _dns2_internal_tcp_send (obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DNS_COMMAND_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dns2_sync (DNS2 *obj) {
|
||||||
|
int res, res_poll;
|
||||||
|
struct pollfd poller;
|
||||||
|
int wanted_events;
|
||||||
|
int events;
|
||||||
|
|
||||||
|
res = dns2_async (obj);
|
||||||
|
|
||||||
|
while (res == DNS_COMMAND_POLL) {
|
||||||
|
poller.fd = dns2_get_socket (obj);
|
||||||
|
poller.revents = 0;
|
||||||
|
poller.events = 0;
|
||||||
|
/* FIXME AQUI */
|
||||||
|
wanted_events = dns2_get_socket_poll_flags (obj);
|
||||||
|
if (wanted_events == DNS_POLL_WANT_READ) {
|
||||||
|
poller.events = POLLIN;
|
||||||
|
} else if (wanted_events == DNS_POLL_WANT_WRITE) {
|
||||||
|
poller.events = POLLOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
res_poll = poll (&poller, 1, 30);
|
||||||
|
|
||||||
|
if (res_poll == 0) {
|
||||||
|
/* Si no ocurrió evento, mandar a llamar por timeouts: */
|
||||||
|
res = dns2_check_timeout (obj);
|
||||||
|
continue;
|
||||||
|
} else if (res_poll < 0) {
|
||||||
|
if (errno == EINTR) continue;
|
||||||
|
/* Caso contrario, salir */
|
||||||
|
res = DNS_COMMAND_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ocurrió un evento, revisar cuál se quería y retornarlo para el continue */
|
||||||
|
if (poller.revents & POLLOUT) {
|
||||||
|
events = DNS_POLL_WANT_WRITE;
|
||||||
|
} else if (poller.revents & POLLIN) {
|
||||||
|
events = DNS_POLL_WANT_READ;
|
||||||
|
}
|
||||||
|
res = dns2_async_continue (obj, events);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Leer el paquete respuesta y regresarlo */
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _dns2_internal_tcp_start_connect (DNS2 *obj) {
|
||||||
|
NameServer *ns;
|
||||||
|
int flags;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
ns = (NameServer *) obj->current_ns->data;
|
||||||
|
ns->socket = socket (ns->server_addr.ss_family, SOCK_STREAM, 0);
|
||||||
|
|
||||||
|
/* Si no pude crear un socket, ni siquiera intentar con el siguiente nameserver */
|
||||||
|
if (ns->socket < 0) {
|
||||||
|
obj->state = DNS_STATE_FREE;
|
||||||
|
obj->direction = DNS_POLL_WANT_NONE;
|
||||||
|
|
||||||
|
return DNS_COMMAND_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Aplicar el no-bloqueante */
|
||||||
|
flags = fcntl (ns->socket, F_GETFL, 0);
|
||||||
|
flags = flags | O_NONBLOCK;
|
||||||
|
fcntl (ns->socket, F_SETFL, flags);
|
||||||
|
|
||||||
|
/* Ejecutar el connect */
|
||||||
|
res = connect (ns->socket, (struct sockaddr *) &ns->server_addr, ns->addr_size);
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
if (errno == EINPROGRESS) {
|
||||||
|
obj->direction = DNS_POLL_WANT_WRITE;
|
||||||
|
return DNS_COMMAND_POLL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _dns2_internal_tcp_next_or_error (obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tengo conexión, pasar de estado */
|
||||||
|
obj->state = DNS_STATE_TCP;
|
||||||
|
obj->direction = DNS_POLL_WANT_WRITE;
|
||||||
|
|
||||||
|
return dns2_async_continue (obj, DNS_POLL_WANT_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int _dns2_internal_tcp_connect_continue (DNS2 *obj) {
|
||||||
|
int optval;
|
||||||
|
socklen_t optlen;
|
||||||
|
int res;
|
||||||
|
NameServer *ns;
|
||||||
|
|
||||||
|
ns = (NameServer *) obj->current_ns->data;
|
||||||
|
optlen = sizeof (optval);
|
||||||
|
|
||||||
|
res = getsockopt (ns->socket, SOL_SOCKET, SO_ERROR, &optval, &optlen);
|
||||||
|
|
||||||
|
if (res < 0 || optval != 0) {
|
||||||
|
return _dns2_internal_tcp_next_or_error (obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pasar de estado */
|
||||||
|
obj->state = DNS_STATE_TCP;
|
||||||
|
obj->direction = DNS_POLL_WANT_WRITE;
|
||||||
|
|
||||||
|
return dns2_async_continue (obj, DNS_POLL_WANT_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int _dns2_internal_tcp_next_or_error (DNS2 *obj) {
|
||||||
|
NameServer *ns;
|
||||||
|
|
||||||
|
ns = (NameServer *) obj->current_ns->data;
|
||||||
|
close (ns->socket);
|
||||||
|
ns->socket = -1;
|
||||||
|
|
||||||
|
obj->current_ns = g_list_next (obj->current_ns);
|
||||||
|
if (obj->current_ns != NULL) {
|
||||||
|
obj->state = DNS_STATE_TCP_CONNECT;
|
||||||
|
|
||||||
|
return _dns2_internal_tcp_start_connect (obj);
|
||||||
|
} else {
|
||||||
|
obj->state = DNS_STATE_FREE;
|
||||||
|
obj->direction = DNS_POLL_WANT_NONE;
|
||||||
|
|
||||||
|
/* Como ya no hay más nameservers en la lista, entregar error */
|
||||||
|
return DNS_COMMAND_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int _dns2_internal_udp_next_or_error (DNS2 *obj) {
|
||||||
|
/* Los sockets UDP no se cierran, se dejan para usar después */
|
||||||
|
|
||||||
|
obj->current_ns = g_list_next (obj->current_ns);
|
||||||
|
if (obj->current_ns != NULL) {
|
||||||
|
/* Aún hay siguiente servidor, intentarlo con éste */
|
||||||
|
obj->state = DNS_STATE_UDP;
|
||||||
|
|
||||||
|
return _dns2_internal_udp_create (obj);
|
||||||
|
} else {
|
||||||
|
/* Como ya no hay mas en la lista, esperar al timeout */
|
||||||
|
obj->direction = DNS_POLL_WANT_READ;
|
||||||
|
|
||||||
|
return DNS_COMMAND_POLL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int _dns2_internal_udp_send (DNS2 *obj) {
|
||||||
|
int res;
|
||||||
|
void *data;
|
||||||
|
int data_length;
|
||||||
|
NameServer *ns;
|
||||||
|
|
||||||
|
ns = (NameServer *) obj->current_ns->data;
|
||||||
|
|
||||||
|
data_length = dns_packet_get_data (obj->packet, (unsigned char **) &data);
|
||||||
|
|
||||||
|
clock_gettime (CLOCK_MONOTONIC, &obj->last_time_sent);
|
||||||
|
|
||||||
|
res = sendto (ns->socket, data, data_length, 0, (struct sockaddr *) &ns->server_addr, ns->addr_size);
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
if (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR) {
|
||||||
|
obj->direction = DNS_POLL_WANT_WRITE;
|
||||||
|
|
||||||
|
return DNS_COMMAND_POLL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _dns2_internal_udp_next_or_error (obj);
|
||||||
|
} else if (res < data_length) {
|
||||||
|
/* Envié la petición incompleta, manejar este error */
|
||||||
|
|
||||||
|
return _dns2_internal_udp_next_or_error (obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cambio de estado, esperar la lectura */
|
||||||
|
obj->direction = DNS_POLL_WANT_READ;
|
||||||
|
|
||||||
|
return dns2_async_continue (obj, DNS_POLL_WANT_READ);
|
||||||
|
}
|
||||||
|
|
||||||
|
int _dns2_internal_tcp_send (DNS2 *obj) {
|
||||||
|
int res;
|
||||||
|
void *data;
|
||||||
|
int data_length;
|
||||||
|
unsigned char data_plus[8192 + 2];
|
||||||
|
uint16_t t16;
|
||||||
|
NameServer *ns;
|
||||||
|
|
||||||
|
ns = (NameServer *) obj->current_ns->data;
|
||||||
|
data_length = dns_packet_get_data (obj->packet, (unsigned char **) &data);
|
||||||
|
|
||||||
|
/* En TCP, agregar la longitud previa a los datos */
|
||||||
|
t16 = htons (data_length);
|
||||||
|
memcpy (data_plus, &t16, 2);
|
||||||
|
|
||||||
|
memcpy (&data_plus[2], data, data_length);
|
||||||
|
|
||||||
|
res = write (ns->socket, data_plus, data_length + 2);
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
if (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR) {
|
||||||
|
obj->direction = DNS_POLL_WANT_WRITE;
|
||||||
|
|
||||||
|
return DNS_COMMAND_POLL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _dns2_internal_tcp_next_or_error (obj);
|
||||||
|
} else if (res < data_length) {
|
||||||
|
/* Envié la petición incompleta, manejar este error */
|
||||||
|
|
||||||
|
return _dns2_internal_tcp_next_or_error (obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cambio de estado, esperar la lectura */
|
||||||
|
obj->direction = DNS_POLL_WANT_READ;
|
||||||
|
|
||||||
|
return dns2_async_continue (obj, DNS_POLL_WANT_READ);
|
||||||
|
}
|
||||||
|
|
||||||
|
int _dns2_internal_udp_recv (DNS2 *obj) {
|
||||||
|
int res;
|
||||||
|
struct sockaddr_storage origen;
|
||||||
|
socklen_t origen_size;
|
||||||
|
unsigned char buffer[8192];
|
||||||
|
NameServer *ns;
|
||||||
|
|
||||||
|
ns = (NameServer *) obj->current_ns->data;
|
||||||
|
|
||||||
|
origen_size = sizeof (origen);
|
||||||
|
res = recvfrom (ns->socket, buffer, sizeof (buffer), 0, (struct sockaddr *) &origen, &origen_size);
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
if (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR) {
|
||||||
|
obj->direction = DNS_POLL_WANT_READ;
|
||||||
|
|
||||||
|
return DNS_COMMAND_POLL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ¿Otro error en un socket UDP? -> Mejor seguir esperando una lectura */
|
||||||
|
|
||||||
|
obj->direction = DNS_POLL_WANT_READ;
|
||||||
|
|
||||||
|
return DNS_COMMAND_POLL;
|
||||||
|
} /* Revisar que el paquete venga del mismo origen a donde envié la petición original */
|
||||||
|
else if (sockaddr_cmp ((struct sockaddr *) &origen, (struct sockaddr *) &ns->server_addr) == 0) {
|
||||||
|
/* Por el momento, dumpear la información
|
||||||
|
int g;
|
||||||
|
printf ("Respuesta recibida:\n");
|
||||||
|
for (g = 0; g < res; g++) {
|
||||||
|
printf ("%02x", ((unsigned int) buffer[g]));
|
||||||
|
}
|
||||||
|
|
||||||
|
printf ("\nEnd response\n");*/
|
||||||
|
|
||||||
|
if (obj->packet_response != NULL) {
|
||||||
|
dns_packet_free_full (obj->packet_response);
|
||||||
|
obj->packet_response = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj->packet_response = dns_packet_create_response (SOCK_DGRAM, buffer, res);
|
||||||
|
|
||||||
|
if (obj->packet_response == NULL) {
|
||||||
|
/* Como no es válida la respuesta, pasar al siguiente servidor */
|
||||||
|
return _dns2_internal_udp_next_or_error (obj);
|
||||||
|
} else {
|
||||||
|
if (obj->packet_response->header.id != obj->packet->header.id) {
|
||||||
|
/* Esta no es la respuesta que esperaba */
|
||||||
|
obj->direction = DNS_POLL_WANT_READ;
|
||||||
|
|
||||||
|
return DNS_COMMAND_POLL;
|
||||||
|
}
|
||||||
|
/* Finalizar la petición */
|
||||||
|
dns2_clean_network (obj);
|
||||||
|
|
||||||
|
obj->state = DNS_STATE_FREE;
|
||||||
|
obj->direction = DNS_POLL_WANT_NONE;
|
||||||
|
|
||||||
|
return DNS_COMMAND_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
obj->direction = DNS_POLL_WANT_READ;
|
||||||
|
|
||||||
|
return DNS_COMMAND_POLL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _dns2_internal_tcp_recv (DNS2 *obj) {
|
||||||
|
int res;
|
||||||
|
uint16_t t16;
|
||||||
|
NameServer *ns;
|
||||||
|
|
||||||
|
ns = (NameServer *) obj->current_ns->data;
|
||||||
|
|
||||||
|
res = read (ns->socket, &obj->buffer_read[obj->buffer_read_pos], sizeof (obj->buffer_read) - obj->buffer_read_pos);
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
if (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR) {
|
||||||
|
obj->direction = DNS_POLL_WANT_READ;
|
||||||
|
|
||||||
|
return DNS_COMMAND_POLL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Si obtuvimos un error, pasar al siguiente servidor */
|
||||||
|
return _dns2_internal_tcp_next_or_error (obj);
|
||||||
|
} else if (res == 0) {
|
||||||
|
/* ¿Socket cerrado? -> Pasar al siguiente servidor */
|
||||||
|
return _dns2_internal_tcp_next_or_error (obj);
|
||||||
|
} else {
|
||||||
|
/* Por el momento, dumpear la información
|
||||||
|
int g;
|
||||||
|
printf ("Bytes recibidos por TCP:\n");
|
||||||
|
for (g = obj->buffer_read_pos; g < obj->buffer_read_pos + res; g++) {
|
||||||
|
printf ("%02x", ((unsigned int) obj->buffer_read[g]));
|
||||||
|
}
|
||||||
|
|
||||||
|
printf ("\nFin bytes\n");*/
|
||||||
|
|
||||||
|
/* Incrementar el buffer */
|
||||||
|
obj->buffer_read_pos = obj->buffer_read_pos + res;
|
||||||
|
|
||||||
|
/* Validar la longitud de los datos TCP aquí */
|
||||||
|
memcpy (&t16, obj->buffer_read, 2);
|
||||||
|
t16 = ntohs (t16);
|
||||||
|
|
||||||
|
if (t16 + 2 < obj->buffer_read_pos) {
|
||||||
|
/* Datos incompletos TCP, seguir haciendo POLL */
|
||||||
|
obj->direction = DNS_POLL_WANT_READ;
|
||||||
|
|
||||||
|
return DNS_COMMAND_POLL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj->packet_response != NULL) {
|
||||||
|
dns_packet_free_full (obj->packet_response);
|
||||||
|
obj->packet_response = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj->packet_response = dns_packet_create_response (SOCK_STREAM, &obj->buffer_read[2], res - 2);
|
||||||
|
|
||||||
|
if (obj->packet_response == NULL) {
|
||||||
|
/* Error de parseo */
|
||||||
|
return _dns2_internal_tcp_next_or_error (obj);
|
||||||
|
} else {
|
||||||
|
/* If packet == good */
|
||||||
|
//dns2_updater_packet_has_valid_tsig (obj, packet);
|
||||||
|
|
||||||
|
/* Pasar de estado */
|
||||||
|
close (ns->socket);
|
||||||
|
ns->socket = -1;
|
||||||
|
|
||||||
|
obj->state = DNS_STATE_FREE;
|
||||||
|
obj->direction = DNS_POLL_WANT_NONE;
|
||||||
|
|
||||||
|
return DNS_COMMAND_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int _dns2_internal_udp_create (DNS2 *obj) {
|
||||||
|
NameServer *ns;
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
obj->direction = DNS_POLL_WANT_WRITE;
|
||||||
|
|
||||||
|
ns = (NameServer *) obj->current_ns->data;
|
||||||
|
|
||||||
|
/* Crear el socket UDP de una buena vez */
|
||||||
|
if (ns->socket < 0) {
|
||||||
|
ns->socket = socket (ns->server_addr.ss_family, SOCK_DGRAM, 0);
|
||||||
|
|
||||||
|
/* Aplicar el no-bloqueante */
|
||||||
|
flags = fcntl (ns->socket, F_GETFL, 0);
|
||||||
|
flags = flags | O_NONBLOCK;
|
||||||
|
fcntl (ns->socket, F_SETFL, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Si no pude crear un socket, tenemos un serio problema */
|
||||||
|
if (ns->socket < 0) {
|
||||||
|
obj->state = DNS_STATE_FREE;
|
||||||
|
obj->direction = DNS_POLL_WANT_NONE;
|
||||||
|
|
||||||
|
return DNS_COMMAND_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dns2_async_continue (obj, DNS_POLL_WANT_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns2_sign_tsig (DNS2 *obj, const char *keyname, const char *signature, const char *algorithm) {
|
||||||
|
DNSRR *rr;
|
||||||
|
|
||||||
|
/* TODO: Revisar si deberíamos liberar el auth_signature anterior */
|
||||||
|
rr = dns2_rr_create_tsig (keyname, signature, algorithm);
|
||||||
|
|
||||||
|
if (rr != NULL) {
|
||||||
|
obj->auth_signature = rr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Crear un objeto */
|
||||||
|
DNS2 *dns2_new (void) {
|
||||||
|
DNS2 *obj;
|
||||||
|
|
||||||
|
obj = (DNS2 *) malloc (sizeof (DNS2));
|
||||||
|
|
||||||
|
if (obj == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj->packet = NULL;
|
||||||
|
|
||||||
|
obj->state = DNS_STATE_FREE;
|
||||||
|
obj->direction = DNS_POLL_WANT_NONE;
|
||||||
|
obj->nameservers = NULL;
|
||||||
|
obj->timeout = 5;
|
||||||
|
|
||||||
|
obj->current_ns = NULL;
|
||||||
|
obj->zone = NULL;
|
||||||
|
obj->force_use_tcp = 0;
|
||||||
|
obj->want_recursion = 0;
|
||||||
|
obj->buffer_read_pos = 0;
|
||||||
|
obj->auth_signature = NULL;
|
||||||
|
obj->packet_response = NULL;
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns2_add_nserver (DNS2 *obj, const char *ip) {
|
||||||
|
int res;
|
||||||
|
struct sockaddr_in v4;
|
||||||
|
struct sockaddr_in6 v6;
|
||||||
|
NameServer *ns;
|
||||||
|
|
||||||
|
memset (&v4, 0, sizeof (v4));
|
||||||
|
res = inet_pton (AF_INET, ip, &v4.sin_addr);
|
||||||
|
if (res > 0) {
|
||||||
|
/* Es una IP de 4 */
|
||||||
|
ns = (NameServer *) malloc (sizeof (NameServer));
|
||||||
|
|
||||||
|
if (ns == NULL) return;
|
||||||
|
|
||||||
|
v4.sin_family = AF_INET;
|
||||||
|
v4.sin_port = htons (53);
|
||||||
|
|
||||||
|
memcpy (&ns->server_addr, &v4, sizeof (v4));
|
||||||
|
ns->addr_size = sizeof (v4);
|
||||||
|
strncpy (ns->name, ip, sizeof (ns->name));
|
||||||
|
ns->socket = -1;
|
||||||
|
|
||||||
|
obj->nameservers = g_list_append (obj->nameservers, ns);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset (&v6, 0, sizeof (v6));
|
||||||
|
res = inet_pton (AF_INET6, ip, &v6.sin6_addr);
|
||||||
|
if (res > 0) {
|
||||||
|
ns = (NameServer *) malloc (sizeof (NameServer));
|
||||||
|
|
||||||
|
if (ns == NULL) return;
|
||||||
|
|
||||||
|
v6.sin6_family = AF_INET6;
|
||||||
|
v6.sin6_port = htons (53);
|
||||||
|
|
||||||
|
memcpy (&ns->server_addr, &v6, sizeof (v6));
|
||||||
|
ns->addr_size = sizeof (v6);
|
||||||
|
strncpy (ns->name, ip, sizeof (ns->name));
|
||||||
|
|
||||||
|
obj->nameservers = g_list_append (obj->nameservers, ns);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns2_clean_network (DNS2 *obj) {
|
||||||
|
GList *g;
|
||||||
|
NameServer *ns;
|
||||||
|
|
||||||
|
for (g = obj->nameservers; g != NULL; g = g->next) {
|
||||||
|
ns = (NameServer *) g->data;
|
||||||
|
|
||||||
|
if (ns->socket >= 0) {
|
||||||
|
close (ns->socket);
|
||||||
|
ns->socket = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns2_free (DNS2 *obj) {
|
||||||
|
|
||||||
|
/* Cerrar el socket, si es que hay alguno abierto */
|
||||||
|
dns2_clean_network (obj);
|
||||||
|
|
||||||
|
/* Liberar la lista de NS */
|
||||||
|
g_list_free_full (obj->nameservers, (GDestroyNotify) free);
|
||||||
|
|
||||||
|
if (obj->zone != NULL) {
|
||||||
|
free (obj->zone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ahora, buscar si el auth_signature ya está en la lista de additionals. Si lo está, no hay necesidad de liberarlo, se liberará cuando se libere el paquete */
|
||||||
|
if (obj->auth_signature != NULL) {
|
||||||
|
/* Liberar la firma, porque está fuera del paquete */
|
||||||
|
dns2_rr_free (obj->auth_signature);
|
||||||
|
obj->auth_signature = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj->packet != NULL) {
|
||||||
|
dns_packet_free_full (obj->packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj->packet_response != NULL) {
|
||||||
|
dns_packet_free_full (obj->packet_response);
|
||||||
|
}
|
||||||
|
|
||||||
|
free (obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dns2_check_timeout (DNS2 *obj) {
|
||||||
|
struct timespec now;
|
||||||
|
double d;
|
||||||
|
|
||||||
|
if (obj->state != DNS_STATE_UDP) return DNS_COMMAND_POLL;
|
||||||
|
|
||||||
|
clock_gettime (CLOCK_MONOTONIC, &now);
|
||||||
|
|
||||||
|
d = _dns2_diff_timespec (&now, &obj->last_time_sent);
|
||||||
|
if (obj->current_ns->next == NULL) {
|
||||||
|
/* Si estamos al borde del último servidor, necesitamos el timeout largo */
|
||||||
|
if (d > (double) obj->timeout) {
|
||||||
|
/* Como cayó el timeout largo, incrementar los retries y regresar al primer servidor */
|
||||||
|
obj->retry_count++;
|
||||||
|
if (obj->retry_count >= 3) {
|
||||||
|
/* Ya agoté todos los reintentos y servidores, bye */
|
||||||
|
dns2_clean_network (obj);
|
||||||
|
obj->current_ns = NULL;
|
||||||
|
|
||||||
|
return DNS_COMMAND_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj->current_ns = obj->nameservers;
|
||||||
|
return _dns2_internal_udp_create (obj);
|
||||||
|
}
|
||||||
|
} else if (d > 1.0) {
|
||||||
|
/* 1 segundo entre servidor y servidor */
|
||||||
|
return _dns2_internal_udp_next_or_error (obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DNS_COMMAND_POLL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dns2_get_socket (DNS2 *obj) {
|
||||||
|
NameServer *ns;
|
||||||
|
|
||||||
|
if (obj == NULL) return -1;
|
||||||
|
|
||||||
|
if (obj->state == DNS_STATE_FREE) return -1;
|
||||||
|
|
||||||
|
ns = (NameServer *) obj->current_ns->data;
|
||||||
|
|
||||||
|
return ns->socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dns2_get_socket_poll_flags (DNS2 *obj) {
|
||||||
|
if (obj == NULL) return -1;
|
||||||
|
|
||||||
|
if (obj->direction == DNS_POLL_WANT_READ) {
|
||||||
|
return DNS_POLL_WANT_READ;
|
||||||
|
} else if (obj->direction == DNS_POLL_WANT_WRITE) {
|
||||||
|
return DNS_POLL_WANT_WRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns2_set_use_tcp (DNS2 *obj) {
|
||||||
|
if (obj == NULL) return;
|
||||||
|
|
||||||
|
obj->force_use_tcp = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DNSRR **dns2_get_answers_from_response (DNS2 *obj) {
|
||||||
|
if (obj == NULL) return NULL;
|
||||||
|
if (obj->packet_response == NULL) return NULL;
|
||||||
|
|
||||||
|
return dns_packet_get_answers (obj->packet_response);
|
||||||
|
}
|
||||||
|
|
||||||
|
DNSRR **dns2_get_authority_from_response (DNS2 *obj) {
|
||||||
|
if (obj == NULL) return NULL;
|
||||||
|
if (obj->packet_response == NULL) return NULL;
|
||||||
|
|
||||||
|
return dns_packet_get_authority (obj->packet_response);
|
||||||
|
}
|
||||||
|
|
||||||
|
DNSRR **dns2_get_additional_from_response (DNS2 *obj) {
|
||||||
|
if (obj == NULL) return NULL;
|
||||||
|
if (obj->packet_response == NULL) return NULL;
|
||||||
|
|
||||||
|
return dns_packet_get_additional (obj->packet_response);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dns2_get_rcode (DNS2 *obj) {
|
||||||
|
if (obj == NULL) return -1;
|
||||||
|
if (obj->packet_response == NULL) return -1;
|
||||||
|
|
||||||
|
return obj->packet_response->header.rcode;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
#ifndef __DNS2_H__
|
||||||
|
#define __DNS2_H__
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "rr.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
DNS_RESOLVER = 0,
|
||||||
|
DNS_UPDATER
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
DNS_STATE_FREE = 0,
|
||||||
|
DNS_STATE_UDP,
|
||||||
|
DNS_STATE_TCP_CONNECT,
|
||||||
|
DNS_STATE_TCP
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
DNS_COMMAND_ERROR_UNSIGNED = -2,
|
||||||
|
DNS_COMMAND_ERROR = -1,
|
||||||
|
DNS_COMMAND_POLL = 0,
|
||||||
|
DNS_COMMAND_SUCCESS = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DNS_POLL_WANT_NONE 0x00
|
||||||
|
#define DNS_POLL_WANT_READ 0x01
|
||||||
|
#define DNS_POLL_WANT_WRITE 0x02
|
||||||
|
|
||||||
|
typedef struct _DNS2 DNS2;
|
||||||
|
|
||||||
|
DNS2 *dns2_resolver_new (int recursion);
|
||||||
|
void dns2_resolver_set_question (DNS2 *resolver, const char *name, int type, int klass);
|
||||||
|
|
||||||
|
DNS2 *dns2_updater_new (const char *zone);
|
||||||
|
void dns2_updater_add (DNS2 *updater, DNSRR *rr);
|
||||||
|
|
||||||
|
void dns2_add_nserver (DNS2 *obj, const char *ip);
|
||||||
|
void dns2_free (DNS2 *obj);
|
||||||
|
|
||||||
|
void dns2_sign_tsig (DNS2 *obj, const char *keyname, const char *signature, const char *algorithm);
|
||||||
|
|
||||||
|
int dns2_sync (DNS2 *obj);
|
||||||
|
int dns2_async (DNS2 *obj);
|
||||||
|
int dns2_async_continue (DNS2 *obj, int happen);
|
||||||
|
|
||||||
|
int dns2_check_timeout (DNS2 *obj);
|
||||||
|
int dns2_get_socket (DNS2 *obj);
|
||||||
|
int dns2_get_socket_poll_flags (DNS2 *obj);
|
||||||
|
void dns2_set_use_tcp (DNS2 *obj);
|
||||||
|
|
||||||
|
DNSRR **dns2_get_answers_from_response (DNS2 *obj);
|
||||||
|
DNSRR **dns2_get_authority_from_response (DNS2 *obj);
|
||||||
|
DNSRR **dns2_get_additional_from_response (DNS2 *obj);
|
||||||
|
|
||||||
|
int dns2_get_rcode (DNS2 *obj);
|
||||||
|
|
||||||
|
#endif /* __DNS2_H__ */
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,152 @@
|
||||||
|
/* GLIB - Library of useful routines for C programming
|
||||||
|
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Modified by the GLib Team and others 1997-2000. See the AUTHORS
|
||||||
|
* file for a list of people on the GLib Team. See the ChangeLog
|
||||||
|
* files for a list of changes. These files are distributed with
|
||||||
|
* GLib at ftp://ftp.gtk.org/pub/gtk/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __G_LIST_H__
|
||||||
|
#define __G_LIST_H__
|
||||||
|
|
||||||
|
#define G_GNUC_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
|
||||||
|
|
||||||
|
typedef void * gpointer;
|
||||||
|
typedef const void * gconstpointer;
|
||||||
|
typedef void (*GDestroyNotify) (gpointer data);
|
||||||
|
typedef void (*GFunc) (gpointer data, gpointer user_data);
|
||||||
|
typedef int (*GCompareDataFunc) (gconstpointer a, gconstpointer b, gpointer user_data);
|
||||||
|
typedef int (*GCompareFunc) (gconstpointer a, gconstpointer b);
|
||||||
|
typedef gpointer (*GCopyFunc) (gconstpointer src, gpointer data);
|
||||||
|
|
||||||
|
typedef struct _GList GList;
|
||||||
|
|
||||||
|
struct _GList
|
||||||
|
{
|
||||||
|
gpointer data;
|
||||||
|
GList *next;
|
||||||
|
GList *prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Doubly linked lists
|
||||||
|
*/
|
||||||
|
|
||||||
|
GList* g_list_alloc (void) G_GNUC_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
void g_list_free (GList *list);
|
||||||
|
|
||||||
|
void g_list_free_1 (GList *list);
|
||||||
|
#define g_list_free1 g_list_free_1
|
||||||
|
|
||||||
|
void g_list_free_full (GList *list,
|
||||||
|
GDestroyNotify free_func);
|
||||||
|
|
||||||
|
GList* g_list_append (GList *list,
|
||||||
|
gpointer data) G_GNUC_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
GList* g_list_prepend (GList *list,
|
||||||
|
gpointer data) G_GNUC_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
GList* g_list_insert (GList *list,
|
||||||
|
gpointer data,
|
||||||
|
int position) G_GNUC_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
GList* g_list_insert_sorted (GList *list,
|
||||||
|
gpointer data,
|
||||||
|
GCompareFunc func) G_GNUC_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
GList* g_list_insert_sorted_with_data (GList *list,
|
||||||
|
gpointer data,
|
||||||
|
GCompareDataFunc func,
|
||||||
|
gpointer user_data) G_GNUC_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
GList* g_list_insert_before (GList *list,
|
||||||
|
GList *sibling,
|
||||||
|
gpointer data) G_GNUC_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
GList* g_list_concat (GList *list1,
|
||||||
|
GList *list2) G_GNUC_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
GList* g_list_remove (GList *list,
|
||||||
|
gconstpointer data) G_GNUC_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
GList* g_list_remove_all (GList *list,
|
||||||
|
gconstpointer data) G_GNUC_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
GList* g_list_remove_link (GList *list,
|
||||||
|
GList *llink) G_GNUC_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
GList* g_list_delete_link (GList *list,
|
||||||
|
GList *link_) G_GNUC_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
GList* g_list_reverse (GList *list) G_GNUC_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
GList* g_list_copy (GList *list) G_GNUC_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
|
||||||
|
GList* g_list_copy_deep (GList *list,
|
||||||
|
GCopyFunc func,
|
||||||
|
gpointer user_data) G_GNUC_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
|
||||||
|
GList* g_list_nth (GList *list,
|
||||||
|
unsigned int n);
|
||||||
|
|
||||||
|
GList* g_list_nth_prev (GList *list,
|
||||||
|
unsigned int n);
|
||||||
|
|
||||||
|
GList* g_list_find (GList *list,
|
||||||
|
gconstpointer data);
|
||||||
|
|
||||||
|
GList* g_list_find_custom (GList *list,
|
||||||
|
gconstpointer data,
|
||||||
|
GCompareFunc func);
|
||||||
|
|
||||||
|
int g_list_position (GList *list,
|
||||||
|
GList *llink);
|
||||||
|
|
||||||
|
int g_list_index (GList *list,
|
||||||
|
gconstpointer data);
|
||||||
|
|
||||||
|
GList* g_list_last (GList *list);
|
||||||
|
|
||||||
|
GList* g_list_first (GList *list);
|
||||||
|
|
||||||
|
unsigned int g_list_length (GList *list);
|
||||||
|
|
||||||
|
void g_list_foreach (GList *list,
|
||||||
|
GFunc func,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
GList* g_list_sort (GList *list,
|
||||||
|
GCompareFunc compare_func) G_GNUC_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
GList* g_list_sort_with_data (GList *list,
|
||||||
|
GCompareDataFunc compare_func,
|
||||||
|
gpointer user_data) G_GNUC_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
gpointer g_list_nth_data (GList *list,
|
||||||
|
unsigned int n);
|
||||||
|
|
||||||
|
|
||||||
|
#define g_list_previous(list) ((list) ? (((GList *)(list))->prev) : NULL)
|
||||||
|
#define g_list_next(list) ((list) ? (((GList *)(list))->next) : NULL)
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __G_LIST_H__ */
|
|
@ -0,0 +1,40 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
#include "header.h"
|
||||||
|
#include "constants.h"
|
||||||
|
|
||||||
|
static uint16_t next_packet_id = 0;
|
||||||
|
|
||||||
|
static uint16_t dns_header_get_next_packet_id (void) {
|
||||||
|
if (next_packet_id == 0) {
|
||||||
|
next_packet_id = 1 + ((int) (65534.0 * rand () / (RAND_MAX + 1.0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return next_packet_id++;;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns_header_init (DNSHeader *header) {
|
||||||
|
header->id = dns_header_get_next_packet_id ();
|
||||||
|
//header->id = 0x72de;
|
||||||
|
header->qr = QR_QUERY;
|
||||||
|
header->opcode = OPCODE_QUERY;
|
||||||
|
header->aa = 0;
|
||||||
|
header->tc = 0;
|
||||||
|
header->rd = 1;
|
||||||
|
header->ra = 0;
|
||||||
|
header->z = 0;
|
||||||
|
header->ad = 0;
|
||||||
|
header->cd = 0;
|
||||||
|
header->rcode = RCODE_NOERROR;
|
||||||
|
header->qdcount = 1;
|
||||||
|
header->ancount = 0;
|
||||||
|
header->nscount = 0;
|
||||||
|
header->arcount = 0;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
#ifndef __HEADER_H__
|
||||||
|
#define __HEADER_H__
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DNS Packet Header class
|
||||||
|
*
|
||||||
|
* This class handles parsing and constructing DNS Packet Headers as defined
|
||||||
|
* by section 4.1.1 of RFC1035.
|
||||||
|
*
|
||||||
|
* DNS header format - RFC1035 section 4.1.1
|
||||||
|
* DNS header format - RFC4035 section 3.2
|
||||||
|
*
|
||||||
|
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
||||||
|
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
* | ID |
|
||||||
|
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
* |QR| Opcode |AA|TC|RD|RA| Z|AD|CD| RCODE |
|
||||||
|
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
* | QDCOUNT |
|
||||||
|
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
* | ANCOUNT |
|
||||||
|
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
* | NSCOUNT |
|
||||||
|
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
* | ARCOUNT |
|
||||||
|
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
*
|
||||||
|
* @category Networking
|
||||||
|
* @package Net_DNS2
|
||||||
|
* @author Mike Pultz <mike@mikepultz.com>
|
||||||
|
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
|
||||||
|
* @link http://pear.php.net/package/Net_DNS2
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t id; // 16 bit - identifier
|
||||||
|
uint8_t qr; // 1 bit - 0 = query, 1 = response
|
||||||
|
uint8_t opcode; // 4 bit - op code
|
||||||
|
uint8_t aa; // 1 bit - Authoritative Answer
|
||||||
|
uint8_t tc; // 1 bit - TrunCation
|
||||||
|
uint8_t rd; // 1 bit - Recursion Desired
|
||||||
|
uint8_t ra; // 1 bit - Recursion Available
|
||||||
|
uint8_t z; // 1 bit - Reserved
|
||||||
|
uint8_t ad; // 1 bit - Authentic Data (RFC4035)
|
||||||
|
uint8_t cd; // 1 bit - Checking Disabled (RFC4035)
|
||||||
|
uint8_t rcode; // 4 bit - Response code
|
||||||
|
uint16_t qdcount; // 16 bit - entries in the question section
|
||||||
|
uint16_t ancount; // 16 bit - resource records in the answer section
|
||||||
|
uint16_t nscount; // 16 bit - name server rr in the authority records section
|
||||||
|
uint16_t arcount; // 16 bit - rr's in the additional records section
|
||||||
|
} DNSHeader;
|
||||||
|
|
||||||
|
void dns_header_init (DNSHeader *header);
|
||||||
|
|
||||||
|
#endif /* __HEADER_H__ */
|
|
@ -0,0 +1,24 @@
|
||||||
|
dns2_resolver_new
|
||||||
|
dns2_resolver_set_question
|
||||||
|
dns2_updater_new
|
||||||
|
dns2_updater_add
|
||||||
|
dns2_add_nserver
|
||||||
|
dns2_free
|
||||||
|
dns2_sign_tsig
|
||||||
|
dns2_sync
|
||||||
|
dns2_async
|
||||||
|
dns2_async_continue
|
||||||
|
dns2_check_timeout
|
||||||
|
dns2_get_socket
|
||||||
|
dns2_get_socket_poll_flags
|
||||||
|
dns2_set_use_tcp
|
||||||
|
dns2_get_answers_from_response
|
||||||
|
dns2_get_authority_from_response
|
||||||
|
dns2_get_additional_from_response
|
||||||
|
dns2_get_rcode
|
||||||
|
dns2_rr_create_a
|
||||||
|
dns2_rr_create_aaaa
|
||||||
|
dns2_rr_create_ns
|
||||||
|
dns2_rr_create_tsig
|
||||||
|
dns2_rr_dup
|
||||||
|
dns2_rr_free
|
|
@ -0,0 +1,601 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "constants.h"
|
||||||
|
#include "packet.h"
|
||||||
|
#include "question.h"
|
||||||
|
#include "rr.h"
|
||||||
|
|
||||||
|
void dns_rr_pack_data (DNSRR *rr, DNSPacket *packet);
|
||||||
|
DNSRR * dns_rr_unpack_data (DNSPacket *packet);
|
||||||
|
|
||||||
|
DNSPacket *dns_packet_create_request (const char *name, int type, int klass) {
|
||||||
|
DNSPacket *req;
|
||||||
|
DNSQuestion *q;
|
||||||
|
|
||||||
|
req = (DNSPacket *) malloc (sizeof (DNSPacket));
|
||||||
|
|
||||||
|
if (req == NULL) return NULL;
|
||||||
|
|
||||||
|
dns_header_init (&req->header);
|
||||||
|
|
||||||
|
q = dns_question_create (name, type, klass);
|
||||||
|
|
||||||
|
if (q == NULL) {
|
||||||
|
free (req);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
req->questions = g_list_append (NULL, q);
|
||||||
|
|
||||||
|
req->authority = NULL;
|
||||||
|
req->answers = NULL;
|
||||||
|
req->additional = NULL;
|
||||||
|
req->rdlength = 0;
|
||||||
|
|
||||||
|
req->labels = NULL;
|
||||||
|
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
DNSPacket *dns_packet_create_response (int type, unsigned char *data, int size_data) {
|
||||||
|
DNSPacket *res;
|
||||||
|
DNSRR *rr;
|
||||||
|
|
||||||
|
int g;
|
||||||
|
|
||||||
|
res = (DNSPacket *) malloc (sizeof (DNSPacket));
|
||||||
|
|
||||||
|
if (res == NULL) return NULL;
|
||||||
|
|
||||||
|
memset (res, 0, sizeof (DNSPacket));
|
||||||
|
|
||||||
|
res->answer_socket_type = type;
|
||||||
|
|
||||||
|
memcpy (res->rdata, data, size_data);
|
||||||
|
res->rdlength = size_data;
|
||||||
|
res->rdread = 0;
|
||||||
|
|
||||||
|
if (dns_header_init_from_packet (&res->header, res) < 0) {
|
||||||
|
dns_packet_free_full (res);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Revisar el bit de truncamiento */
|
||||||
|
|
||||||
|
/* Parsear las preguntas */
|
||||||
|
for (g = 0; g < res->header.qdcount; g++) {
|
||||||
|
if (dns_question_parse_question_from_packet (res) < 0) {
|
||||||
|
dns_packet_free_full (res);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parsear los answers */
|
||||||
|
for (g = 0; g < res->header.ancount; g++) {
|
||||||
|
rr = dns_rr_unpack_data (res);
|
||||||
|
|
||||||
|
if (rr == NULL) {
|
||||||
|
dns_packet_free_full (res);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
res->answers = g_list_append (res->answers, rr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parsear los authority */
|
||||||
|
for (g = 0; g < res->header.nscount; g++) {
|
||||||
|
rr = dns_rr_unpack_data (res);
|
||||||
|
|
||||||
|
if (rr == NULL) {
|
||||||
|
dns_packet_free_full (res);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
res->authority = g_list_append (res->authority, rr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parsear los aditional */
|
||||||
|
for (g = 0; g < res->header.arcount; g++) {
|
||||||
|
rr = dns_rr_unpack_data (res);
|
||||||
|
|
||||||
|
if (rr == NULL) {
|
||||||
|
dns_packet_free_full (res);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
res->additional = g_list_append (res->additional, rr);
|
||||||
|
}
|
||||||
|
|
||||||
|
dns_packet_recount_items (res);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dns_packet_get_data (DNSPacket *packet, unsigned char **data) {
|
||||||
|
if (data != NULL) {
|
||||||
|
*data = packet->rdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
return packet->rdlength;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns_packet_pack_data (DNSPacket *packet) {
|
||||||
|
GList *g;
|
||||||
|
DNSQuestion *qq;
|
||||||
|
DNSRR *rr;
|
||||||
|
|
||||||
|
/* Reiniciar desde 0 */
|
||||||
|
packet->rdlength = 0;
|
||||||
|
|
||||||
|
dns_header_pack_data (&packet->header, packet);
|
||||||
|
|
||||||
|
g = packet->questions;
|
||||||
|
while (g != NULL) {
|
||||||
|
qq = (DNSQuestion *) g->data;
|
||||||
|
|
||||||
|
dns_question_pack_data (qq, packet);
|
||||||
|
|
||||||
|
g = g->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
g = packet->answers;
|
||||||
|
while (g != NULL) {
|
||||||
|
rr = (DNSRR *) g->data;
|
||||||
|
|
||||||
|
dns_rr_pack_data (rr, packet);
|
||||||
|
|
||||||
|
g = g->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
g = packet->authority;
|
||||||
|
while (g != NULL) {
|
||||||
|
rr = (DNSRR *) g->data;
|
||||||
|
|
||||||
|
dns_rr_pack_data (rr, packet);
|
||||||
|
|
||||||
|
g = g->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
g = packet->additional;
|
||||||
|
while (g != NULL) {
|
||||||
|
rr = (DNSRR *) g->data;
|
||||||
|
|
||||||
|
dns_rr_pack_data (rr, packet);
|
||||||
|
|
||||||
|
g = g->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dns_packet_search_label (gconstpointer left, gconstpointer right) {
|
||||||
|
PacketLabel *a = (PacketLabel *) left;
|
||||||
|
PacketLabel *b = (PacketLabel *) right;
|
||||||
|
|
||||||
|
return strcmp (a->name, b->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dns_packet_append_word (DNSPacket *packet, const char *name) {
|
||||||
|
const char *ending;
|
||||||
|
PacketLabel *new_label;
|
||||||
|
uint8_t t8;
|
||||||
|
|
||||||
|
ending = strchr (name, '.');
|
||||||
|
if (ending == NULL) {
|
||||||
|
ending = name + strlen (name);
|
||||||
|
}
|
||||||
|
|
||||||
|
new_label = (PacketLabel *) malloc (sizeof (PacketLabel));
|
||||||
|
|
||||||
|
if (new_label == NULL) {
|
||||||
|
/* Oops, error */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy (new_label->name, name, sizeof (new_label->name));
|
||||||
|
new_label->offset = packet->rdlength;
|
||||||
|
|
||||||
|
packet->labels = g_list_append (packet->labels, new_label);
|
||||||
|
|
||||||
|
/* Copiar solo la palabra */
|
||||||
|
t8 = (ending - name);
|
||||||
|
packet->rdata[packet->rdlength] = t8;
|
||||||
|
memcpy (&packet->rdata[packet->rdlength + 1], name, t8);
|
||||||
|
|
||||||
|
packet->rdlength += t8 + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns_packet_pack_name (DNSPacket *packet, const char *name) {
|
||||||
|
char * dot_pos;
|
||||||
|
|
||||||
|
while (dot_pos = strchr (name, '.'), dot_pos != NULL) {
|
||||||
|
/* Buscar esta palabra en nuestro diccionario de palabras */
|
||||||
|
name = dot_pos + 1;
|
||||||
|
|
||||||
|
/* Agregar esta palabra al diccionario de etiquetas */
|
||||||
|
dns_packet_append_word (packet, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* La palabra restante, copiarla */
|
||||||
|
if (name[0] != 0) {
|
||||||
|
dns_packet_append_word (packet, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
packet->rdata[packet->rdlength] = 0;
|
||||||
|
packet->rdlength += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns_packet_compress_name (DNSPacket *packet, char *name) {
|
||||||
|
PacketLabel temp, *found;
|
||||||
|
char * dot_pos;
|
||||||
|
GList *search;
|
||||||
|
uint16_t t16;
|
||||||
|
|
||||||
|
while (dot_pos = strchr (name, '.'), dot_pos != NULL) {
|
||||||
|
/* Buscar esta palabra en nuestro diccionario de palabras */
|
||||||
|
|
||||||
|
strncpy (temp.name, name, sizeof (temp.name));
|
||||||
|
|
||||||
|
search = g_list_find_custom (packet->labels, &temp, dns_packet_search_label);
|
||||||
|
|
||||||
|
if (search != NULL) {
|
||||||
|
found = (PacketLabel *) search->data;
|
||||||
|
|
||||||
|
t16 = htons (0xc000 | found->offset);
|
||||||
|
|
||||||
|
memcpy (&packet->rdata[packet->rdlength], &t16, 2);
|
||||||
|
packet->rdlength += 2;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Agregar esta palabra al direccionario de etiquetas */
|
||||||
|
dns_packet_append_word (packet, name);
|
||||||
|
name = dot_pos + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* La palabra restante, copiarla */
|
||||||
|
if (name[0] != 0) {
|
||||||
|
dns_packet_append_word (packet, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
packet->rdata[packet->rdlength] = 0;
|
||||||
|
packet->rdlength += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DNSPacket *dns_packet_clone_simple (DNSPacket *packet) {
|
||||||
|
DNSPacket *clone;
|
||||||
|
|
||||||
|
clone = (DNSPacket *) malloc (sizeof (DNSPacket));
|
||||||
|
|
||||||
|
if (clone == NULL) return NULL;
|
||||||
|
|
||||||
|
memcpy (&clone->header, &packet->header, sizeof (DNSHeader));
|
||||||
|
|
||||||
|
clone->questions = g_list_copy (packet->questions);
|
||||||
|
clone->answers = g_list_copy (packet->answers);
|
||||||
|
clone->authority = g_list_copy (packet->authority);
|
||||||
|
clone->additional = g_list_copy (packet->additional);
|
||||||
|
|
||||||
|
clone->labels = NULL;
|
||||||
|
|
||||||
|
clone->rdlength = 0;
|
||||||
|
|
||||||
|
/* NOTA: No se copian las labels */
|
||||||
|
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns_packet_free_simple (DNSPacket *packet) {
|
||||||
|
/* Liberar las estructuras, excepto los datos que no duplicamos */
|
||||||
|
g_list_free_full (packet->labels, (GDestroyNotify) free);
|
||||||
|
|
||||||
|
g_list_free (packet->questions);
|
||||||
|
g_list_free (packet->answers);
|
||||||
|
g_list_free (packet->authority);
|
||||||
|
g_list_free (packet->additional);
|
||||||
|
|
||||||
|
free (packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns_packet_free_full (DNSPacket *packet) {
|
||||||
|
g_list_free_full (packet->labels, (GDestroyNotify) free);
|
||||||
|
|
||||||
|
g_list_free_full (packet->questions, (GDestroyNotify) dns_question_free);
|
||||||
|
g_list_free_full (packet->answers, (GDestroyNotify) dns2_rr_free);
|
||||||
|
g_list_free_full (packet->authority, (GDestroyNotify) dns2_rr_free);
|
||||||
|
g_list_free_full (packet->additional, (GDestroyNotify) dns2_rr_free);
|
||||||
|
|
||||||
|
free (packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns_packet_reset (DNSPacket *packet) {
|
||||||
|
g_list_free_full (packet->labels, (GDestroyNotify) free);
|
||||||
|
packet->labels = NULL;
|
||||||
|
|
||||||
|
packet->rdlength = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dns_packet_expand_name (unsigned char *name, DNSPacket *packet, int *offset) {
|
||||||
|
int name_len = 0;
|
||||||
|
uint8_t t8;
|
||||||
|
uint16_t t16;
|
||||||
|
int local_offset;
|
||||||
|
int ptr, ptr_inicio;
|
||||||
|
int g;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (name_len >= 256) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packet->rdlength < (*offset) + 1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
t8 = packet->rdata[*offset];
|
||||||
|
|
||||||
|
if (t8 == 0) {
|
||||||
|
name[name_len] = 0;
|
||||||
|
|
||||||
|
(*offset)++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
} else if ((t8 & 0xc0) == 0xc0) {
|
||||||
|
/* Tenemos un apuntador */
|
||||||
|
if (packet->rdlength < (*offset) + 2) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy (&t16, &packet->rdata[*offset], sizeof (t16));
|
||||||
|
t16 = ntohs (t16);
|
||||||
|
|
||||||
|
ptr = t16 & 0x3fff;
|
||||||
|
ptr_inicio = ptr;
|
||||||
|
if (dns_packet_expand_name (&name[name_len], packet, &ptr) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sumar a la longitud de nombres lo recibido del apuntador */
|
||||||
|
name_len = name_len + (ptr - ptr_inicio);
|
||||||
|
(*offset) += 2;
|
||||||
|
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
(*offset)++;
|
||||||
|
|
||||||
|
if (packet->rdlength < (*offset) + t8) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Una palabra */
|
||||||
|
for (g = *offset; g < t8 + *offset; g++) {
|
||||||
|
name[name_len] = packet->rdata[g];
|
||||||
|
name_len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
name[name_len] = '.';
|
||||||
|
name_len++;
|
||||||
|
|
||||||
|
(*offset) += t8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Limpiar el último punto */
|
||||||
|
if (name[name_len - 1] == '.') {
|
||||||
|
name[name_len - 1] = 0;
|
||||||
|
name_len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dns_packet_expand_name_simple (unsigned char *name, unsigned char *buffer, int buffer_size) {
|
||||||
|
int name_len = 0;
|
||||||
|
uint8_t t8;
|
||||||
|
int g;
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (name_len >= 256) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer_size < offset + 1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
t8 = buffer[offset];
|
||||||
|
offset++;
|
||||||
|
|
||||||
|
if (t8 == 0) {
|
||||||
|
/* Fin del nombre */
|
||||||
|
name[name_len] = 0;
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
} else {
|
||||||
|
if (buffer_size < offset + t8) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Una palabra */
|
||||||
|
for (g = offset; g < t8 + offset; g++) {
|
||||||
|
name[name_len] = buffer[g];
|
||||||
|
name_len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
name[name_len] = '.';
|
||||||
|
name_len++;
|
||||||
|
|
||||||
|
offset += t8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Limpiar el último punto */
|
||||||
|
if (name[name_len - 1] == '.') {
|
||||||
|
name[name_len - 1] = 0;
|
||||||
|
name_len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns_header_pack_data (DNSHeader *header, DNSPacket *packet) {
|
||||||
|
unsigned char *buf;
|
||||||
|
uint16_t t16;
|
||||||
|
uint8_t t8;
|
||||||
|
|
||||||
|
buf = &packet->rdata[packet->rdlength];
|
||||||
|
|
||||||
|
/* Copiar el ID */
|
||||||
|
t16 = htons (header->id);
|
||||||
|
memcpy (&buf[0], &t16, sizeof (t16));
|
||||||
|
|
||||||
|
t8 = (header->qr << 7) | (header->opcode << 3) | (header->aa << 2) | (header->tc << 1) | (header->rd);
|
||||||
|
buf[2] = t8;
|
||||||
|
|
||||||
|
t8 = (header->ra << 7) | (header->ad << 5) | (header->cd << 4) | header->rcode;
|
||||||
|
buf[3] = t8;
|
||||||
|
|
||||||
|
t16 = htons (header->qdcount);
|
||||||
|
memcpy (&buf[4], &t16, sizeof (t16));
|
||||||
|
|
||||||
|
t16 = htons (header->ancount);
|
||||||
|
memcpy (&buf[6], &t16, sizeof (t16));
|
||||||
|
|
||||||
|
t16 = htons (header->nscount);
|
||||||
|
memcpy (&buf[8], &t16, sizeof (t16));
|
||||||
|
|
||||||
|
t16 = htons (header->arcount);
|
||||||
|
memcpy (&buf[10], &t16, sizeof (t16));
|
||||||
|
|
||||||
|
packet->rdlength += DNS_HEADER_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dns_header_init_from_packet (DNSHeader *header, DNSPacket *packet) {
|
||||||
|
uint16_t t16;
|
||||||
|
uint8_t t8;
|
||||||
|
unsigned char *buf;
|
||||||
|
|
||||||
|
buf = &packet->rdata[packet->rdread];
|
||||||
|
|
||||||
|
if (packet->rdlength < packet->rdread + DNS_HEADER_SIZE) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy (&t16, &buf[0], sizeof (t16));
|
||||||
|
header->id = ntohs (t16);
|
||||||
|
|
||||||
|
t8 = buf[2];
|
||||||
|
|
||||||
|
header->qr = (t8 >> 7) & 0x1;
|
||||||
|
header->opcode = (t8 >> 3) & 0xf;
|
||||||
|
header->aa = (t8 >> 2) & 0x1;
|
||||||
|
header->tc = (t8 >> 1) & 0x1;
|
||||||
|
header->rd = t8 & 0x1;
|
||||||
|
|
||||||
|
t8 = buf[3];
|
||||||
|
header->ra = (t8 >> 7) & 0x1;
|
||||||
|
header->z = (t8 >> 6) & 0x1;
|
||||||
|
header->ad = (t8 >> 5) & 0x1;
|
||||||
|
header->cd = (t8 >> 4) & 0x1;
|
||||||
|
header->rcode = t8 & 0xf;
|
||||||
|
|
||||||
|
memcpy (&t16, &buf[4], sizeof (t16));
|
||||||
|
header->qdcount = ntohs (t16);
|
||||||
|
|
||||||
|
memcpy (&t16, &buf[6], sizeof (t16));
|
||||||
|
header->ancount = ntohs (t16);
|
||||||
|
|
||||||
|
memcpy (&t16, &buf[8], sizeof (t16));
|
||||||
|
header->nscount = ntohs (t16);
|
||||||
|
|
||||||
|
memcpy (&t16, &buf[10], sizeof (t16));
|
||||||
|
header->arcount = ntohs (t16);
|
||||||
|
|
||||||
|
packet->rdread += DNS_HEADER_SIZE;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns_packet_recount_items (DNSPacket *packet) {
|
||||||
|
if (packet == NULL) return;
|
||||||
|
|
||||||
|
packet->header.qdcount = g_list_length (packet->questions);
|
||||||
|
packet->header.ancount = g_list_length (packet->answers);
|
||||||
|
packet->header.nscount = g_list_length (packet->authority);
|
||||||
|
packet->header.arcount = g_list_length (packet->additional);
|
||||||
|
}
|
||||||
|
|
||||||
|
DNSRR **dns_packet_get_answers (DNSPacket *packet) {
|
||||||
|
DNSRR **array;
|
||||||
|
GList *g;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
dns_packet_recount_items (packet);
|
||||||
|
|
||||||
|
if (packet->header.ancount == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
array = (DNSRR **) malloc ((packet->header.ancount + 1) * sizeof (DNSRR *));
|
||||||
|
|
||||||
|
for (n = 0, g = packet->answers; g != NULL; g = g->next, n++) {
|
||||||
|
array[n] = (DNSRR *) g->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
array[n] = NULL;
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
DNSRR **dns_packet_get_authority (DNSPacket *packet) {
|
||||||
|
DNSRR **array;
|
||||||
|
GList *g;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
dns_packet_recount_items (packet);
|
||||||
|
|
||||||
|
if (packet->header.nscount == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
array = (DNSRR **) malloc ((packet->header.nscount + 1) * sizeof (DNSRR *));
|
||||||
|
|
||||||
|
for (n = 0, g = packet->authority; g != NULL; g = g->next, n++) {
|
||||||
|
array[n] = (DNSRR *) g->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
array[n] = NULL;
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
DNSRR **dns_packet_get_additional (DNSPacket *packet) {
|
||||||
|
DNSRR **array;
|
||||||
|
GList *g;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
dns_packet_recount_items (packet);
|
||||||
|
|
||||||
|
if (packet->header.arcount == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
array = (DNSRR **) malloc ((packet->header.arcount + 1) * sizeof (DNSRR *));
|
||||||
|
|
||||||
|
for (n = 0, g = packet->additional; g != NULL; g = g->next, n++) {
|
||||||
|
array[n] = (DNSRR *) g->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
array[n] = NULL;
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
#ifndef __PACKET_H__
|
||||||
|
#define __PACKET_H__
|
||||||
|
|
||||||
|
#include "glist.h"
|
||||||
|
#include "header.h"
|
||||||
|
#include "rr.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char name[256];
|
||||||
|
uint16_t offset;
|
||||||
|
} PacketLabel;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char rdata[8192];
|
||||||
|
|
||||||
|
int rdlength;
|
||||||
|
int rdread;
|
||||||
|
|
||||||
|
DNSHeader header;
|
||||||
|
|
||||||
|
GList *questions;
|
||||||
|
|
||||||
|
GList *answers;
|
||||||
|
|
||||||
|
GList *authority;
|
||||||
|
|
||||||
|
GList *additional;
|
||||||
|
|
||||||
|
GList *labels;
|
||||||
|
|
||||||
|
int answer_socket_type;
|
||||||
|
/* Las respuestas tienen:
|
||||||
|
answer_from
|
||||||
|
answer_socket_type
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
} DNSPacket;
|
||||||
|
|
||||||
|
DNSPacket *dns_packet_create_request (const char *name, int type, int klass);
|
||||||
|
DNSPacket *dns_packet_create_response (int type, unsigned char *data, int size_data);
|
||||||
|
DNSPacket *dns_packet_clone_simple (DNSPacket *packet);
|
||||||
|
void dns_packet_compress_name (DNSPacket *packet, char *name);
|
||||||
|
void dns_packet_pack_name (DNSPacket *packet, const char *name);
|
||||||
|
void dns_packet_pack_data (DNSPacket *packet);
|
||||||
|
int dns_packet_get_data (DNSPacket *packet, unsigned char **data);
|
||||||
|
void dns_packet_free_simple (DNSPacket *packet);
|
||||||
|
void dns_packet_free_full (DNSPacket *packet);
|
||||||
|
void dns_header_pack_data (DNSHeader *header, DNSPacket *packet);
|
||||||
|
int dns_header_init_from_packet (DNSHeader *header, DNSPacket *packet);
|
||||||
|
void dns_packet_reset (DNSPacket *packet);
|
||||||
|
int dns_packet_expand_name (unsigned char *name, DNSPacket *packet, int *offset);
|
||||||
|
int dns_packet_expand_name_simple (unsigned char *name, unsigned char *buffer, int buffer_size);
|
||||||
|
|
||||||
|
void dns_rr_pack_generate_signature (DNSRR *signature, DNSPacket *packet);
|
||||||
|
|
||||||
|
void dns_packet_recount_items (DNSPacket *packet);
|
||||||
|
DNSRR **dns_packet_get_answers (DNSPacket *packet);
|
||||||
|
DNSRR **dns_packet_get_authority (DNSPacket *packet);
|
||||||
|
DNSRR **dns_packet_get_additional (DNSPacket *packet);
|
||||||
|
|
||||||
|
#endif /* __PACKET_H__ */
|
|
@ -0,0 +1,87 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
#include "constants.h"
|
||||||
|
#include "question.h"
|
||||||
|
#include "packet.h"
|
||||||
|
|
||||||
|
DNSQuestion * dns_question_create (const char *name, int type, int klass) {
|
||||||
|
DNSQuestion *question;
|
||||||
|
|
||||||
|
question = (DNSQuestion *) malloc (sizeof (DNSQuestion));
|
||||||
|
|
||||||
|
if (question == NULL) return NULL;
|
||||||
|
|
||||||
|
memset (question, 0, sizeof (DNSQuestion));
|
||||||
|
|
||||||
|
strncpy (question->qname, name, 255);
|
||||||
|
|
||||||
|
question->qtype = type;
|
||||||
|
question->qklass = klass;
|
||||||
|
|
||||||
|
return question;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns_question_pack_data (DNSQuestion *question, DNSPacket *packet) {
|
||||||
|
uint16_t t16;
|
||||||
|
|
||||||
|
dns_packet_compress_name (packet, question->qname);
|
||||||
|
|
||||||
|
t16 = htons (question->qtype);
|
||||||
|
memcpy (&packet->rdata[packet->rdlength], &t16, 2);
|
||||||
|
packet->rdlength += 2;
|
||||||
|
|
||||||
|
t16 = htons (question->qklass);
|
||||||
|
memcpy (&packet->rdata[packet->rdlength], &t16, 2);
|
||||||
|
packet->rdlength += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns_question_free (DNSQuestion *question) {
|
||||||
|
free (question);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dns_question_parse_question_from_packet (DNSPacket *packet) {
|
||||||
|
DNSQuestion *question;
|
||||||
|
uint16_t t16;
|
||||||
|
|
||||||
|
question = (DNSQuestion *) malloc (sizeof (DNSQuestion));
|
||||||
|
|
||||||
|
if (question == NULL) return -1;
|
||||||
|
|
||||||
|
memset (question, 0, sizeof (DNSQuestion));
|
||||||
|
|
||||||
|
if (dns_packet_expand_name (question->qname, packet, &packet->rdread) < 0) {
|
||||||
|
dns_question_free (question);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packet->rdlength < packet->rdread + 4) {
|
||||||
|
dns_question_free (question);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy (&t16, &packet->rdata[packet->rdread], sizeof (t16));
|
||||||
|
question->qtype = ntohs (t16);
|
||||||
|
packet->rdread += 2;
|
||||||
|
|
||||||
|
memcpy (&t16, &packet->rdata[packet->rdread], sizeof (t16));
|
||||||
|
question->qklass = ntohs (t16);
|
||||||
|
packet->rdread += 2;
|
||||||
|
|
||||||
|
if (question->qklass != RR_CLASS_IN &&
|
||||||
|
question->qklass != RR_CLASS_CH &&
|
||||||
|
question->qklass != RR_CLASS_HS) {
|
||||||
|
dns_question_free (question);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Validar el qtype */
|
||||||
|
|
||||||
|
/* Anexar a la lista de preguntas */
|
||||||
|
packet->questions = g_list_append (packet->questions, question);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
#ifndef __QUESTION_H__
|
||||||
|
#define __QUESTION_H__
|
||||||
|
|
||||||
|
#include "packet.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char qname[256];
|
||||||
|
|
||||||
|
int qtype;
|
||||||
|
int qklass;
|
||||||
|
} DNSQuestion;
|
||||||
|
|
||||||
|
DNSQuestion * dns_question_create (const char *name, int type, int klass);
|
||||||
|
void dns_question_pack_data (DNSQuestion *question, DNSPacket *packet);
|
||||||
|
void dns_question_free (DNSQuestion *question);
|
||||||
|
int dns_question_parse_question_from_packet (DNSPacket *packet);
|
||||||
|
|
||||||
|
#endif /* __QUESTION_H__ */
|
|
@ -0,0 +1,57 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include <sys/poll.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "dns2.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "packet.h"
|
||||||
|
#include "constants.h"
|
||||||
|
#include "glist.h"
|
||||||
|
#include "rr.h"
|
||||||
|
|
||||||
|
#include "dns2-private.h"
|
||||||
|
|
||||||
|
DNS2 *dns2_resolver_new (int recursion) {
|
||||||
|
DNS2 *resolver;
|
||||||
|
|
||||||
|
resolver = dns2_new ();
|
||||||
|
|
||||||
|
if (resolver == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolver->want_recursion = recursion;
|
||||||
|
resolver->type = DNS_RESOLVER;
|
||||||
|
|
||||||
|
return resolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns2_resolver_set_question (DNS2 *resolver, const char *name, int type, int klass) {
|
||||||
|
if (resolver->packet != NULL) {
|
||||||
|
dns_packet_free_full (resolver->packet);
|
||||||
|
resolver->packet = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolver->packet = dns_packet_create_request (name, type, klass);
|
||||||
|
|
||||||
|
if (resolver->packet == NULL) {
|
||||||
|
/* FIXME: ¿Qué hacemos? */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolver->packet->header.opcode = OPCODE_QUERY;
|
||||||
|
resolver->packet->header.rd = resolver->want_recursion;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,726 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <openssl/hmac.h>
|
||||||
|
|
||||||
|
#include "rr.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "constants.h"
|
||||||
|
#include "packet.h"
|
||||||
|
|
||||||
|
/* ----- Creadores ----- */
|
||||||
|
|
||||||
|
DNSRR *dns2_rr_create_a (const char *name, int klass, int ttl, struct in_addr address) {
|
||||||
|
DNSRR *rr;
|
||||||
|
|
||||||
|
rr = (DNSRR *) malloc (sizeof (DNSRR));
|
||||||
|
|
||||||
|
if (rr == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy (rr->name, name, sizeof (rr->name));
|
||||||
|
dns2_trim_name (rr->name);
|
||||||
|
|
||||||
|
if (rr->name[0] == 0) {
|
||||||
|
free (rr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rr->type = RR_TYPE_A;
|
||||||
|
rr->klass = klass;
|
||||||
|
rr->ttl = ttl;
|
||||||
|
|
||||||
|
/* Copiar la IP */
|
||||||
|
memcpy (&rr->a.address, &address, sizeof (rr->a.address));
|
||||||
|
|
||||||
|
return rr;
|
||||||
|
}
|
||||||
|
|
||||||
|
DNSRR *dns2_rr_create_tsig (const char *name, const char *signature, const char *algorithm) {
|
||||||
|
DNSRR *rr;
|
||||||
|
|
||||||
|
if (strcmp (algorithm, RR_TSIG_HMAC_MD5) != 0 &&
|
||||||
|
strcmp (algorithm, RR_TSIG_HMAC_SHA1) != 0 &&
|
||||||
|
strcmp (algorithm, RR_TSIG_HMAC_SHA224) != 0 &&
|
||||||
|
strcmp (algorithm, RR_TSIG_HMAC_SHA256) != 0 &&
|
||||||
|
strcmp (algorithm, RR_TSIG_HMAC_SHA384) != 0 &&
|
||||||
|
strcmp (algorithm, RR_TSIG_HMAC_SHA512) != 0) {
|
||||||
|
/* Algoritmo no soportado */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rr = (DNSRR *) malloc (sizeof (DNSRR));
|
||||||
|
|
||||||
|
if (rr == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy (rr->name, name, sizeof (rr->name));
|
||||||
|
dns2_trim_name (rr->name);
|
||||||
|
|
||||||
|
if (rr->name[0] == 0) {
|
||||||
|
free (rr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rr->type = RR_TYPE_TSIG;
|
||||||
|
rr->klass = RR_CLASS_ANY;
|
||||||
|
rr->ttl = 0;
|
||||||
|
|
||||||
|
strncpy (rr->tsig.algorithm, algorithm, sizeof (rr->tsig.algorithm));
|
||||||
|
rr->tsig.key = strdup (signature);
|
||||||
|
|
||||||
|
if (rr->tsig.key == NULL) {
|
||||||
|
free (rr->name);
|
||||||
|
free (rr);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// El tiempo tiene que ser UTC
|
||||||
|
// El tiempo son 6 bytes.
|
||||||
|
rr->tsig.time_signed = time (NULL);
|
||||||
|
//exit (1);
|
||||||
|
//rr->tsig.time_signed = 1602910230u;
|
||||||
|
//printf ("Time: %i\n", ((unsigned int) rr->tsig.time_signed));
|
||||||
|
rr->tsig.fudge = 300;
|
||||||
|
rr->tsig.mac_size = 0;
|
||||||
|
rr->tsig.original_id = 0;
|
||||||
|
|
||||||
|
rr->tsig.error = 0;
|
||||||
|
rr->tsig.other_length = 0;
|
||||||
|
|
||||||
|
return rr;
|
||||||
|
}
|
||||||
|
|
||||||
|
DNSRR *dns2_rr_create_aaaa (const char *name, int klass, int ttl, struct in6_addr address) {
|
||||||
|
DNSRR *rr;
|
||||||
|
|
||||||
|
rr = (DNSRR *) malloc (sizeof (DNSRR));
|
||||||
|
|
||||||
|
if (rr == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy (rr->name, name, sizeof (rr->name));
|
||||||
|
dns2_trim_name (rr->name);
|
||||||
|
|
||||||
|
if (rr->name[0] == 0) {
|
||||||
|
free (rr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rr->type = RR_TYPE_AAAA;
|
||||||
|
rr->klass = klass;
|
||||||
|
rr->ttl = ttl;
|
||||||
|
|
||||||
|
/* Copiar la IP */
|
||||||
|
memcpy (&rr->aaaa.address, &address, sizeof (rr->aaaa.address));
|
||||||
|
|
||||||
|
return rr;
|
||||||
|
}
|
||||||
|
|
||||||
|
DNSRR *dns2_rr_create_ns (const char *name, int klass, int ttl, const char *nsname) {
|
||||||
|
DNSRR *rr;
|
||||||
|
|
||||||
|
rr = (DNSRR *) malloc (sizeof (DNSRR));
|
||||||
|
|
||||||
|
if (rr == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy (rr->name, name, sizeof (rr->name));
|
||||||
|
dns2_trim_name (rr->name);
|
||||||
|
|
||||||
|
if (rr->name[0] == 0) {
|
||||||
|
free (rr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rr->type = RR_TYPE_NS;
|
||||||
|
rr->klass = klass;
|
||||||
|
rr->ttl = ttl;
|
||||||
|
|
||||||
|
/* Copiar el nombre */
|
||||||
|
memcpy (&rr->ns.name, &nsname, strlen (nsname) + 1);
|
||||||
|
dns2_trim_name (rr->ns.name);
|
||||||
|
|
||||||
|
return rr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----- Empaquetadores ----- */
|
||||||
|
void dns_rr_pack_a_data (DNSRR *rr, DNSPacket *packet) {
|
||||||
|
char *buf;
|
||||||
|
uint16_t t16;
|
||||||
|
|
||||||
|
buf = &packet->rdata[packet->rdlength];
|
||||||
|
|
||||||
|
t16 = htons (4);
|
||||||
|
memcpy (buf, &t16, 2);
|
||||||
|
|
||||||
|
memcpy (&buf[2], &rr->a.address, 4);
|
||||||
|
packet->rdlength += 4 + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns_rr_pack_aaaa_data (DNSRR *rr, DNSPacket *packet) {
|
||||||
|
char *buf;
|
||||||
|
uint16_t t16;
|
||||||
|
|
||||||
|
buf = &packet->rdata[packet->rdlength];
|
||||||
|
|
||||||
|
t16 = htons (16);
|
||||||
|
memcpy (buf, &t16, 2);
|
||||||
|
|
||||||
|
memcpy (&buf[2], &rr->aaaa.address, 16);
|
||||||
|
packet->rdlength += 16 + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dns_rr_sign_hmac (void *data, int data_len, const char *key, const char *algorithm, void *mac) {
|
||||||
|
HMAC_CTX *ctx;
|
||||||
|
const EVP_MD *md_algo;
|
||||||
|
char *decoded_key;
|
||||||
|
size_t key_length;
|
||||||
|
int total_len;
|
||||||
|
int g;
|
||||||
|
|
||||||
|
printf ("About to sign, data is:\n");
|
||||||
|
for (g = 0; g < data_len; g++) {
|
||||||
|
printf ("%02x", (unsigned int) (((unsigned char *) data)[g]));
|
||||||
|
}
|
||||||
|
printf ("\nEnd data sig\n");
|
||||||
|
|
||||||
|
if (strcmp (algorithm, RR_TSIG_HMAC_MD5) == 0) {
|
||||||
|
md_algo = EVP_md5 ();
|
||||||
|
} else if (strcmp (algorithm, RR_TSIG_HMAC_SHA1) == 0) {
|
||||||
|
md_algo = EVP_sha1 ();
|
||||||
|
} else if (strcmp (algorithm, RR_TSIG_HMAC_SHA224) == 0) {
|
||||||
|
md_algo = EVP_sha224 ();
|
||||||
|
} else if (strcmp (algorithm, RR_TSIG_HMAC_SHA256) == 0) {
|
||||||
|
md_algo = EVP_sha256 ();
|
||||||
|
} else if (strcmp (algorithm, RR_TSIG_HMAC_SHA384) == 0) {
|
||||||
|
md_algo = EVP_sha384 ();
|
||||||
|
} else if (strcmp (algorithm, RR_TSIG_HMAC_SHA512) == 0) {
|
||||||
|
md_algo = EVP_sha512 ();
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = HMAC_CTX_new ();
|
||||||
|
|
||||||
|
if (ctx == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (base64_decode (key, (unsigned char **)&decoded_key, &key_length) != 0) {
|
||||||
|
HMAC_CTX_free (ctx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
HMAC_Init_ex (ctx, decoded_key, key_length, md_algo, NULL);
|
||||||
|
|
||||||
|
/* Enviar el mensaje a firmar */
|
||||||
|
HMAC_Update (ctx, data, data_len);
|
||||||
|
|
||||||
|
HMAC_Final (ctx, mac, &total_len);
|
||||||
|
|
||||||
|
HMAC_CTX_free (ctx);
|
||||||
|
|
||||||
|
free (decoded_key);
|
||||||
|
|
||||||
|
return total_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns_rr_pack_tsig_data (DNSRR *rr, DNSPacket *packet) {
|
||||||
|
uint16_t offset_rdlength, t16;
|
||||||
|
uint32_t t32;
|
||||||
|
|
||||||
|
/* Tomar la posición actual para el rdlength */
|
||||||
|
offset_rdlength = packet->rdlength;
|
||||||
|
packet->rdlength += 2;
|
||||||
|
|
||||||
|
/* Agregar el algoritmo sin compresión */
|
||||||
|
dns_packet_pack_name (packet, rr->tsig.algorithm);
|
||||||
|
|
||||||
|
/* Empaquetar el tiempo, fudge y mac_size */
|
||||||
|
t16 = 0;
|
||||||
|
memcpy (&packet->rdata[packet->rdlength], &t16, 2);
|
||||||
|
packet->rdlength += 2;
|
||||||
|
|
||||||
|
t32 = htonl ((intmax_t) rr->tsig.time_signed);
|
||||||
|
memcpy (&packet->rdata[packet->rdlength], &t32, 4);
|
||||||
|
packet->rdlength += 4;
|
||||||
|
|
||||||
|
/* El fudge */
|
||||||
|
t16 = htons (rr->tsig.fudge);
|
||||||
|
memcpy (&packet->rdata[packet->rdlength], &t16, 2);
|
||||||
|
packet->rdlength += 2;
|
||||||
|
|
||||||
|
t16 = htons (rr->tsig.mac_size);
|
||||||
|
memcpy (&packet->rdata[packet->rdlength], &t16, 2);
|
||||||
|
packet->rdlength += 2;
|
||||||
|
|
||||||
|
/* Agregar el MAC */
|
||||||
|
memcpy (&packet->rdata[packet->rdlength], rr->tsig.mac, rr->tsig.mac_size);
|
||||||
|
packet->rdlength += rr->tsig.mac_size;
|
||||||
|
|
||||||
|
/* Copiar el packet id */
|
||||||
|
t16 = htons (packet->header.id);
|
||||||
|
memcpy (&packet->rdata[packet->rdlength], &t16, 2);
|
||||||
|
packet->rdlength += 2;
|
||||||
|
|
||||||
|
/* Error y other length */
|
||||||
|
t16 = htons (rr->tsig.error);
|
||||||
|
memcpy (&packet->rdata[packet->rdlength], &t16, 2);
|
||||||
|
packet->rdlength += 2;
|
||||||
|
|
||||||
|
t16 = htons (rr->tsig.other_length);
|
||||||
|
memcpy (&packet->rdata[packet->rdlength], &t16, 2);
|
||||||
|
packet->rdlength += 2;
|
||||||
|
|
||||||
|
/* Agregar el other_data si other_length > 0 */
|
||||||
|
if (rr->tsig.other_length > 0) {
|
||||||
|
memcpy (&packet->rdata[packet->rdlength], rr->tsig.other_data, rr->tsig.other_length);
|
||||||
|
packet->rdlength += rr->tsig.other_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Regresar a la posición del rdlength y escribir el valor correcto */
|
||||||
|
t16 = htons (packet->rdlength - offset_rdlength - 2);
|
||||||
|
memcpy (&packet->rdata[offset_rdlength], &t16, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns_rr_pack_generate_signature (DNSRR *signature, DNSPacket *packet) {
|
||||||
|
void *data;
|
||||||
|
int data_count;
|
||||||
|
uint16_t t16;
|
||||||
|
uint32_t t32;
|
||||||
|
|
||||||
|
/* Reempaquetar todo el paquete para generar los bytes de la firma */
|
||||||
|
dns_packet_reset (packet);
|
||||||
|
dns_packet_pack_data (packet);
|
||||||
|
|
||||||
|
/* Agregar el nombre del tsig sin compresión */
|
||||||
|
dns_packet_pack_name (packet, signature->name);
|
||||||
|
|
||||||
|
t16 = htons (signature->klass);
|
||||||
|
memcpy (&packet->rdata[packet->rdlength], &t16, 2);
|
||||||
|
packet->rdlength += 2;
|
||||||
|
|
||||||
|
t32 = htonl (signature->ttl);
|
||||||
|
memcpy (&packet->rdata[packet->rdlength], &t32, 4);
|
||||||
|
packet->rdlength += 4;
|
||||||
|
|
||||||
|
/* Agregar el algoritmo sin compresión */
|
||||||
|
dns_packet_pack_name (packet, signature->tsig.algorithm);
|
||||||
|
|
||||||
|
/* Agregar la hora */
|
||||||
|
t16 = 0;
|
||||||
|
memcpy (&packet->rdata[packet->rdlength], &t16, 2);
|
||||||
|
packet->rdlength += 2;
|
||||||
|
|
||||||
|
t32 = htonl ((intmax_t) signature->tsig.time_signed);
|
||||||
|
memcpy (&packet->rdata[packet->rdlength], &t32, 4);
|
||||||
|
packet->rdlength += 4;
|
||||||
|
|
||||||
|
/* El fudge */
|
||||||
|
t16 = htons (signature->tsig.fudge);
|
||||||
|
memcpy (&packet->rdata[packet->rdlength], &t16, 2);
|
||||||
|
packet->rdlength += 2;
|
||||||
|
|
||||||
|
/* Error y other length */
|
||||||
|
t16 = htons (signature->tsig.error);
|
||||||
|
memcpy (&packet->rdata[packet->rdlength], &t16, 2);
|
||||||
|
packet->rdlength += 2;
|
||||||
|
t16 = htons (signature->tsig.other_length);
|
||||||
|
memcpy (&packet->rdata[packet->rdlength], &t16, 2);
|
||||||
|
packet->rdlength += 2;
|
||||||
|
|
||||||
|
/* Agregar el other_data si other_length > 0 */
|
||||||
|
if (signature->tsig.other_length > 0) {
|
||||||
|
memcpy (&packet->rdata[packet->rdlength], signature->tsig.other_data, signature->tsig.other_length);
|
||||||
|
packet->rdlength += signature->tsig.other_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Recuperar la data */
|
||||||
|
data_count = dns_packet_get_data (packet, (unsigned char **)&data);
|
||||||
|
|
||||||
|
/* Realmente firmar la data */
|
||||||
|
signature->tsig.mac_size = dns_rr_sign_hmac (data, data_count, signature->tsig.key, signature->tsig.algorithm, signature->tsig.mac);
|
||||||
|
|
||||||
|
/* Pedir reempaquetar la data, otra vez */
|
||||||
|
dns_packet_reset (packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns_rr_pack_data (DNSRR *rr, DNSPacket *packet) {
|
||||||
|
uint16_t t16;
|
||||||
|
uint32_t t32;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
dns_packet_compress_name (packet, rr->name);
|
||||||
|
|
||||||
|
buf = &packet->rdata[packet->rdlength];
|
||||||
|
|
||||||
|
/*if (rr->type == OPT) {
|
||||||
|
|
||||||
|
} else { */
|
||||||
|
t16 = htons (rr->type);
|
||||||
|
memcpy (&buf[0], &t16, 2);
|
||||||
|
|
||||||
|
t16 = htons (rr->klass);
|
||||||
|
memcpy (&buf[2], &t16, 2);
|
||||||
|
|
||||||
|
t32 = htonl (rr->ttl);
|
||||||
|
memcpy (&buf[4], &t32, 4);
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
packet->rdlength += 8;
|
||||||
|
|
||||||
|
/* Data por tipo */
|
||||||
|
switch (rr->type) {
|
||||||
|
case RR_TYPE_A:
|
||||||
|
dns_rr_pack_a_data (rr, packet);
|
||||||
|
break;
|
||||||
|
case RR_TYPE_AAAA:
|
||||||
|
dns_rr_pack_aaaa_data (rr, packet);
|
||||||
|
break;
|
||||||
|
case RR_TYPE_TSIG:
|
||||||
|
dns_rr_pack_tsig_data (rr, packet);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----- Desempaquetadores ----- */
|
||||||
|
int dns_rr_unpack_a_data (DNSRR *rr, unsigned char *buf, int rd_length) {
|
||||||
|
if (rd_length < 4) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy (&rr->a.address, buf, 4);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dns_rr_unpack_aaaa_data (DNSRR *rr, unsigned char *buf, int rd_length) {
|
||||||
|
if (rd_length < 16) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy (&rr->aaaa.address, buf, 16);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dns_rr_unpack_ns_data (DNSRR *rr, unsigned char *buf, int rd_length, DNSPacket *packet) {
|
||||||
|
/* No hacemos validaciones sobre la longitud porque los nombres son variables */
|
||||||
|
int save;
|
||||||
|
save = buf - packet->rdata;
|
||||||
|
|
||||||
|
if (dns_packet_expand_name (rr->ns.name, packet, &save) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dns_rr_unpack_cname_data (DNSRR *rr, unsigned char *buf, int rd_length, DNSPacket *packet) {
|
||||||
|
/* No hacemos validaciones sobre la longitud porque los nombres son variables */
|
||||||
|
int save;
|
||||||
|
save = buf - packet->rdata;
|
||||||
|
|
||||||
|
if (dns_packet_expand_name (rr->cname.name, packet, &save) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dns_rr_unpack_soa_data (DNSRR *rr, unsigned char *buf, int rd_length, DNSPacket *packet) {
|
||||||
|
int save, start;
|
||||||
|
int tot;
|
||||||
|
uint32_t u32;
|
||||||
|
|
||||||
|
if (rd_length < 20) { /* Al menos 5 enteros de 32 bits cada uno */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
start = save = buf - packet->rdata;
|
||||||
|
if (dns_packet_expand_name (rr->soa.mname, packet, &save) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dns_packet_expand_name (rr->soa.rname, packet, &save) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tot = save - start;
|
||||||
|
if (rd_length - tot < 20) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Leer el serial */
|
||||||
|
memcpy (&u32, &buf[tot], 4);
|
||||||
|
rr->soa.serial = ntohl (u32);
|
||||||
|
|
||||||
|
/* Leer el refresh */
|
||||||
|
memcpy (&u32, &buf[tot + 4], 4);
|
||||||
|
rr->soa.refresh = ntohl (u32);
|
||||||
|
|
||||||
|
/* Leer el retry */
|
||||||
|
memcpy (&u32, &buf[tot + 8], 4);
|
||||||
|
rr->soa.retry = ntohl (u32);
|
||||||
|
|
||||||
|
/* El expire */
|
||||||
|
memcpy (&u32, &buf[tot + 12], 4);
|
||||||
|
rr->soa.expire = ntohl (u32);
|
||||||
|
|
||||||
|
/* El minimum */
|
||||||
|
memcpy (&u32, &buf[tot + 16], 4);
|
||||||
|
rr->soa.minimum = ntohl (u32);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dns_rr_unpack_ptr_data (DNSRR *rr, unsigned char *buf, int rd_length, DNSPacket *packet) {
|
||||||
|
int save;
|
||||||
|
save = buf - packet->rdata;
|
||||||
|
|
||||||
|
if (dns_packet_expand_name (rr->ptr.name, packet, &save) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dns_rr_unpack_mx_data (DNSRR *rr, unsigned char *buf, int rd_length, DNSPacket *packet) {
|
||||||
|
int save;
|
||||||
|
uint16_t u16;
|
||||||
|
|
||||||
|
if (rd_length < 2) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy (&u16, buf, 2);
|
||||||
|
rr->mx.preference = ntohs (u16);
|
||||||
|
|
||||||
|
save = &buf[2] - packet->rdata;
|
||||||
|
|
||||||
|
if (dns_packet_expand_name (rr->mx.name, packet, &save) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dns_rr_unpack_txt_data (DNSRR *rr, unsigned char *buf, int rd_length) {
|
||||||
|
/* En la teoría, un TXT puede contener muchas cadenas,
|
||||||
|
* En la práctica, no creo que ocurra.
|
||||||
|
* Tomar solo la primer cadena */
|
||||||
|
uint8_t txt_len;
|
||||||
|
|
||||||
|
txt_len = buf[0];
|
||||||
|
|
||||||
|
if (txt_len > rd_length - 1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memcpy (rr->txt.txt, &buf[1], txt_len);
|
||||||
|
|
||||||
|
rr->txt.txt[txt_len] = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dns_rr_unpack_tsig_data (DNSRR *rr, unsigned char *buf, int rd_length) {
|
||||||
|
uint32_t t32;
|
||||||
|
uint16_t t16;
|
||||||
|
uint8_t t8;
|
||||||
|
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
offset = 0;
|
||||||
|
t8 = dns_packet_expand_name_simple (rr->tsig.algorithm, buf, rd_length);
|
||||||
|
|
||||||
|
if (t8 < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += t8;
|
||||||
|
|
||||||
|
/* Revisar el time, fudge y mac_size */
|
||||||
|
if (offset + 10 > rd_length) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ¿Ignorar los primeros dos bytes del tiempo? */
|
||||||
|
memcpy (&t16, &buf[offset], 2);
|
||||||
|
|
||||||
|
memcpy (&t32, &buf[offset + 2], 4);
|
||||||
|
rr->tsig.time_signed = ntohl (t32);
|
||||||
|
|
||||||
|
memcpy (&t16, &buf[offset + 6], 2);
|
||||||
|
rr->tsig.fudge = ntohs (t16);
|
||||||
|
|
||||||
|
memcpy (&t16, &buf[offset + 8], 2);
|
||||||
|
rr->tsig.mac_size = ntohs (t16);
|
||||||
|
|
||||||
|
offset += 10;
|
||||||
|
|
||||||
|
/* Copiar el MAC */
|
||||||
|
if (offset + rr->tsig.mac_size > rd_length) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy (&rr->tsig.mac, &buf[offset], rr->tsig.mac_size);
|
||||||
|
offset += rr->tsig.mac_size;
|
||||||
|
|
||||||
|
/* Revisar el packet id, error y other_len */
|
||||||
|
if (offset + 6 > rd_length) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copiar el packet id original */
|
||||||
|
memcpy (&t16, &buf[offset], 2);
|
||||||
|
rr->tsig.original_id = ntohs (t16);
|
||||||
|
|
||||||
|
memcpy (&t16, &buf[offset + 2], 2);
|
||||||
|
rr->tsig.error = ntohs (t16);
|
||||||
|
|
||||||
|
memcpy (&t16, &buf[offset + 4], 2);
|
||||||
|
rr->tsig.other_length = ntohs (t16);
|
||||||
|
|
||||||
|
offset += 6;
|
||||||
|
if (rr->tsig.other_length > 0) {
|
||||||
|
if (offset + rr->tsig.other_length < rd_length) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy (&rr->tsig.other_data, &buf[offset], rr->tsig.other_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DNSRR * dns_rr_unpack_data (DNSPacket *packet) {
|
||||||
|
DNSRR *rr;
|
||||||
|
uint16_t t16;
|
||||||
|
uint32_t t32;
|
||||||
|
unsigned char *buf;
|
||||||
|
int rd_length;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
rr = (DNSRR *) malloc (sizeof (DNSRR));
|
||||||
|
|
||||||
|
if (rr == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset (rr, 0, sizeof (DNSRR));
|
||||||
|
|
||||||
|
if (dns_packet_expand_name (rr->name, packet, &packet->rdread) < 0) {
|
||||||
|
dns2_rr_free (rr);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Asegurar al menos 10 bytes */
|
||||||
|
if (packet->rdlength < packet->rdread + 10) {
|
||||||
|
dns2_rr_free (rr);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = &packet->rdata[packet->rdread];
|
||||||
|
packet->rdread += 10;
|
||||||
|
|
||||||
|
memcpy (&t16, &buf[0], sizeof (t16));
|
||||||
|
rr->type = ntohs (t16);
|
||||||
|
|
||||||
|
memcpy (&t16, &buf[2], sizeof (t16));
|
||||||
|
rr->klass = ntohs (t16);
|
||||||
|
|
||||||
|
memcpy (&t32, &buf[4], sizeof (t32));
|
||||||
|
rr->ttl = ntohl (t32);
|
||||||
|
|
||||||
|
memcpy (&t16, &buf[8], sizeof (t16));
|
||||||
|
rd_length = ntohs (t16);
|
||||||
|
|
||||||
|
if (packet->rdlength < packet->rdread + rd_length) {
|
||||||
|
dns2_rr_free (rr);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = &packet->rdata[packet->rdread];
|
||||||
|
packet->rdread += rd_length;
|
||||||
|
|
||||||
|
res = 0;
|
||||||
|
switch (rr->type) {
|
||||||
|
case RR_TYPE_A:
|
||||||
|
res = dns_rr_unpack_a_data (rr, buf, rd_length);
|
||||||
|
break;
|
||||||
|
case RR_TYPE_AAAA:
|
||||||
|
res = dns_rr_unpack_aaaa_data (rr, buf, rd_length);
|
||||||
|
break;
|
||||||
|
case RR_TYPE_NS:
|
||||||
|
res = dns_rr_unpack_ns_data (rr, buf, rd_length, packet);
|
||||||
|
break;
|
||||||
|
case RR_TYPE_CNAME:
|
||||||
|
res = dns_rr_unpack_cname_data (rr, buf, rd_length, packet);
|
||||||
|
break;
|
||||||
|
case RR_TYPE_SOA:
|
||||||
|
res = dns_rr_unpack_soa_data (rr, buf, rd_length, packet);
|
||||||
|
break;
|
||||||
|
case RR_TYPE_PTR:
|
||||||
|
res = dns_rr_unpack_ptr_data (rr, buf, rd_length, packet);
|
||||||
|
break;
|
||||||
|
case RR_TYPE_MX:
|
||||||
|
res = dns_rr_unpack_mx_data (rr, buf, rd_length, packet);
|
||||||
|
break;
|
||||||
|
case RR_TYPE_TXT:
|
||||||
|
res = dns_rr_unpack_txt_data (rr, buf, rd_length);
|
||||||
|
break;
|
||||||
|
case RR_TYPE_TSIG:
|
||||||
|
res = dns_rr_unpack_tsig_data (rr, buf, rd_length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
dns2_rr_free (rr);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rr;
|
||||||
|
}
|
||||||
|
|
||||||
|
DNSRR *dns2_rr_dup (const DNSRR *rr) {
|
||||||
|
DNSRR *new;
|
||||||
|
|
||||||
|
new = (DNSRR *) malloc (sizeof (DNSRR));
|
||||||
|
if (new == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy (new, rr, sizeof (DNSRR));
|
||||||
|
|
||||||
|
if (rr->type == RR_TYPE_TSIG) {
|
||||||
|
new->tsig.key = strdup (rr->tsig.key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns2_rr_free (DNSRR *rr) {
|
||||||
|
if (rr->type == RR_TYPE_TSIG) {
|
||||||
|
/* La llave se duplicó, liberarla */
|
||||||
|
free (rr->tsig.key);
|
||||||
|
}
|
||||||
|
|
||||||
|
free (rr);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
#ifndef __RR_H__
|
||||||
|
#define __RR_H__
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct in_addr address;
|
||||||
|
} DNSRR_A;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct in6_addr address;
|
||||||
|
} DNSRR_AAAA;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char name[512];
|
||||||
|
} DNSRR_NS;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char name[512];
|
||||||
|
} DNSRR_CNAME;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t preference;
|
||||||
|
unsigned char name[512];
|
||||||
|
} DNSRR_MX;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char txt[512];
|
||||||
|
} DNSRR_TXT;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char mname[512];
|
||||||
|
unsigned char rname[512];
|
||||||
|
uint32_t serial, refresh, retry, expire, minimum;
|
||||||
|
} DNSRR_SOA;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char name[512];
|
||||||
|
} DNSRR_PTR;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char algorithm[512];
|
||||||
|
time_t time_signed;
|
||||||
|
uint16_t fudge;
|
||||||
|
int mac_size;
|
||||||
|
unsigned char mac[512];
|
||||||
|
uint16_t original_id;
|
||||||
|
|
||||||
|
int error;
|
||||||
|
int other_length;
|
||||||
|
unsigned char other_data[512];
|
||||||
|
|
||||||
|
char *key;
|
||||||
|
} DNSRR_TSIG;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char name[512];
|
||||||
|
|
||||||
|
uint16_t type;
|
||||||
|
|
||||||
|
int klass;
|
||||||
|
|
||||||
|
uint32_t ttl;
|
||||||
|
/*int rd_length;
|
||||||
|
void *rdata;*/
|
||||||
|
|
||||||
|
union {
|
||||||
|
DNSRR_A a;
|
||||||
|
DNSRR_AAAA aaaa;
|
||||||
|
DNSRR_TSIG tsig;
|
||||||
|
DNSRR_NS ns;
|
||||||
|
DNSRR_CNAME cname;
|
||||||
|
DNSRR_MX mx;
|
||||||
|
DNSRR_TXT txt;
|
||||||
|
DNSRR_SOA soa;
|
||||||
|
DNSRR_PTR ptr;
|
||||||
|
};
|
||||||
|
} DNSRR;
|
||||||
|
|
||||||
|
DNSRR *dns2_rr_create_a (const char *name, int klass, int ttl, struct in_addr address);
|
||||||
|
DNSRR *dns2_rr_create_aaaa (const char *name, int klass, int ttl, struct in6_addr address);
|
||||||
|
DNSRR *dns2_rr_create_ns (const char *name, int klass, int ttl, const char *nsname);
|
||||||
|
DNSRR *dns2_rr_create_tsig (const char *name, const char *signature, const char *algorithm);
|
||||||
|
DNSRR *dns2_rr_dup (const DNSRR *rr);
|
||||||
|
void dns2_rr_free (DNSRR *rr);
|
||||||
|
|
||||||
|
#endif /* __RR_H__ */
|
|
@ -0,0 +1,157 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include <sys/poll.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "dns2.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "packet.h"
|
||||||
|
#include "constants.h"
|
||||||
|
#include "glist.h"
|
||||||
|
#include "rr.h"
|
||||||
|
|
||||||
|
#include "dns2-private.h"
|
||||||
|
|
||||||
|
DNS2 *dns2_updater_new (const char *zone) {
|
||||||
|
DNS2 *updater;
|
||||||
|
|
||||||
|
updater = dns2_new ();
|
||||||
|
|
||||||
|
if (updater == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
updater->type = DNS_UPDATER;
|
||||||
|
/* Sanitizar "zona" */
|
||||||
|
updater->zone = dns_dup_trim_name (zone);
|
||||||
|
|
||||||
|
if (updater->zone == NULL) {
|
||||||
|
free (updater);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
updater->packet = dns_packet_create_request (updater->zone, RR_TYPE_SOA, RR_CLASS_IN);
|
||||||
|
|
||||||
|
if (updater->packet == NULL) {
|
||||||
|
free (updater->zone);
|
||||||
|
free (updater);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
updater->packet->header.opcode = OPCODE_UPDATE;
|
||||||
|
|
||||||
|
return updater;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dns_updater_check_name (DNS2 *updater, const char *name) {
|
||||||
|
int len, nlen;
|
||||||
|
|
||||||
|
/* TODO: ¿Usar la zona o el question[0]->qname? */
|
||||||
|
len = strlen (updater->zone);
|
||||||
|
|
||||||
|
nlen = strlen (name);
|
||||||
|
if (nlen < len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp (name, updater->zone) == 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp (&name[nlen - len], updater->zone) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name[nlen - len - 1] != '.') {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns2_updater_add (DNS2 *updater, DNSRR *rr) {
|
||||||
|
if (dns_updater_check_name (updater, rr->name) == 0) {
|
||||||
|
/* Fuera de la zona */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_list_find (updater->packet->authority, rr) == NULL) {
|
||||||
|
updater->packet->authority = g_list_append (updater->packet->authority, rr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DNSRR * dns_updater_packet_get_tsig (DNSPacket *response) {
|
||||||
|
int g;
|
||||||
|
GList *last;
|
||||||
|
DNSRR *rr;
|
||||||
|
|
||||||
|
if (response->header.arcount == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
last = g_list_last (response->additional);
|
||||||
|
while (last != NULL) {
|
||||||
|
rr = (DNSRR *) last->data;
|
||||||
|
|
||||||
|
if (rr->type == RR_TYPE_TSIG) {
|
||||||
|
return rr;
|
||||||
|
}
|
||||||
|
|
||||||
|
last = last->prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dns_updater_packet_has_valid_tsig (DNS2 *updater, DNSPacket *response) {
|
||||||
|
DNSRR *rr, *mysig;
|
||||||
|
DNSPacket *dup;
|
||||||
|
|
||||||
|
rr = dns_updater_packet_get_tsig (response);
|
||||||
|
|
||||||
|
if (rr == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updater->auth_signature == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Eliminar temporalmente el rr de la lista */
|
||||||
|
response->additional = g_list_remove (response->additional, rr);
|
||||||
|
response->header.arcount = g_list_length (response->additional);
|
||||||
|
|
||||||
|
/* Recalcular la firma, */
|
||||||
|
mysig = dns2_rr_dup (updater->auth_signature);
|
||||||
|
|
||||||
|
if (mysig->type == RR_TYPE_TSIG /*||
|
||||||
|
mysig->tipo == RR_TYPE_SIG*/) {
|
||||||
|
|
||||||
|
dns_rr_pack_generate_signature (mysig, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Comparar firmas */
|
||||||
|
|
||||||
|
|
||||||
|
/* Re-anexar la firma original */
|
||||||
|
response->additional = g_list_append (response->additional, rr);
|
||||||
|
response->header.arcount = g_list_length (response->additional);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <openssl/bio.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
void dns2_trim_name (char *name) {
|
||||||
|
int g;
|
||||||
|
|
||||||
|
if (name == NULL) return;
|
||||||
|
|
||||||
|
g = 0;
|
||||||
|
while (name[g] != 0 && (name[g] == ' ' || name[g] == '\r' || name[g] == '\n' || name[g] == '\t' || name[g] == '.')) {
|
||||||
|
g++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g < 0) {
|
||||||
|
memmove (name, &name[g], strlen (&name[g]) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hacer trim por el otro lado */
|
||||||
|
g = strlen (name) - 1;
|
||||||
|
while (g > 0 && (name[g] == ' ' || name[g] == '\r' || name[g] == '\n' || name[g] == '\t' || name[g] == '.')) {
|
||||||
|
name[g] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Buscar quitar esta función */
|
||||||
|
char *dns_dup_trim_name (const char *name) {
|
||||||
|
char *zone;
|
||||||
|
int g;
|
||||||
|
|
||||||
|
zone = strdup (name);
|
||||||
|
|
||||||
|
if (zone == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
g = 0;
|
||||||
|
while (zone[g] != 0 && (zone[g] == ' ' || zone[g] == '\r' || zone[g] == '\n' || zone[g] == '\t' || zone[g] == '.')) {
|
||||||
|
g++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g > 0) {
|
||||||
|
memmove (zone, &zone[g], strlen (&zone[g]) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hacer trim por el otro lado */
|
||||||
|
g = strlen (zone) - 1;
|
||||||
|
while (g > 0 && (zone[g] == ' ' || zone[g] == '\r' || zone[g] == '\n' || zone[g] == '\t' || zone[g] == '.')) {
|
||||||
|
zone[g] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return zone;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t calc_decode_length (const char* b64input) { //Calculates the length of a decoded string
|
||||||
|
size_t len = strlen(b64input),
|
||||||
|
padding = 0;
|
||||||
|
|
||||||
|
if (b64input[len-1] == '=' && b64input[len-2] == '=') //last two chars are =
|
||||||
|
padding = 2;
|
||||||
|
else if (b64input[len-1] == '=') //last char is =
|
||||||
|
padding = 1;
|
||||||
|
|
||||||
|
return (len*3)/4 - padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
int base64_decode (const char* b64message, unsigned char** buffer, size_t* length) { //Decodes a base64 encoded string
|
||||||
|
BIO *bio, *b64;
|
||||||
|
|
||||||
|
int decodeLen = calc_decode_length (b64message);
|
||||||
|
*buffer = (unsigned char*) malloc (decodeLen + 1);
|
||||||
|
if (*buffer == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
(*buffer)[decodeLen] = '\0';
|
||||||
|
|
||||||
|
bio = BIO_new_mem_buf (b64message, -1);
|
||||||
|
b64 = BIO_new (BIO_f_base64 ());
|
||||||
|
bio = BIO_push (b64, bio);
|
||||||
|
|
||||||
|
BIO_set_flags (bio, BIO_FLAGS_BASE64_NO_NL); //Do not use newlines to flush buffer
|
||||||
|
*length = BIO_read (bio, *buffer, strlen (b64message));
|
||||||
|
assert (*length == decodeLen); //length should equal decodeLen, else something went horribly wrong
|
||||||
|
BIO_free_all (bio);
|
||||||
|
|
||||||
|
return 0; //success
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Función de Kazuho Oku
|
||||||
|
* https://gist.github.com/kazuho/45eae4f92257daceb73e
|
||||||
|
*/
|
||||||
|
int sockaddr_cmp (struct sockaddr *x, struct sockaddr *y) {
|
||||||
|
#define CMP(a, b) if (a != b) return a < b ? -1 : 1
|
||||||
|
|
||||||
|
CMP(x->sa_family, y->sa_family);
|
||||||
|
|
||||||
|
if (x->sa_family == AF_INET) {
|
||||||
|
struct sockaddr_in *xin = (void*)x, *yin = (void*)y;
|
||||||
|
CMP(ntohl(xin->sin_addr.s_addr), ntohl(yin->sin_addr.s_addr));
|
||||||
|
CMP(ntohs(xin->sin_port), ntohs(yin->sin_port));
|
||||||
|
} else if (x->sa_family == AF_INET6) {
|
||||||
|
struct sockaddr_in6 *xin6 = (void*)x, *yin6 = (void*)y;
|
||||||
|
int r = memcmp (xin6->sin6_addr.s6_addr, yin6->sin6_addr.s6_addr, sizeof(xin6->sin6_addr.s6_addr));
|
||||||
|
if (r != 0) return r;
|
||||||
|
CMP(ntohs(xin6->sin6_port), ntohs(yin6->sin6_port));
|
||||||
|
CMP(xin6->sin6_flowinfo, yin6->sin6_flowinfo);
|
||||||
|
CMP(xin6->sin6_scope_id, yin6->sin6_scope_id);
|
||||||
|
} else {
|
||||||
|
return -1; /* Familia desconocida */
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef CMP
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
#ifndef __UTILS_H__
|
||||||
|
#define __UTILS_H__
|
||||||
|
|
||||||
|
void dns2_trim_name (char *name);
|
||||||
|
char *dns_dup_trim_name (const char *name);
|
||||||
|
int base64_decode (const char* b64message, unsigned char** buffer, size_t* length);
|
||||||
|
int sockaddr_cmp (struct sockaddr *x, struct sockaddr *y);
|
||||||
|
|
||||||
|
#endif /* __UTILS_H__ */
|
||||||
|
|
Loading…
Reference in New Issue