mirror of https://github.com/lukechilds/node.git
Browse Source
Missing functional tests. I'm not sure how to do tests because I don't want to rely on the fact that users have an internet connection.v0.7.4-release
Ryan
16 years ago
46 changed files with 9585 additions and 33 deletions
@ -0,0 +1,14 @@ |
|||||
|
udns*.tar.gz |
||||
|
udns_codes.c |
||||
|
udns.3.html |
||||
|
*.lo |
||||
|
*_s |
||||
|
libudns.so.* |
||||
|
dnsget |
||||
|
ex-rdns |
||||
|
rblcheck |
||||
|
Makefile |
||||
|
config.h |
||||
|
config.status |
||||
|
config.log |
||||
|
build-stamp |
@ -0,0 +1,504 @@ |
|||||
|
GNU LESSER GENERAL PUBLIC LICENSE |
||||
|
Version 2.1, February 1999 |
||||
|
|
||||
|
Copyright (C) 1991, 1999 Free Software Foundation, Inc. |
||||
|
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
Everyone is permitted to copy and distribute verbatim copies |
||||
|
of this license document, but changing it is not allowed. |
||||
|
|
||||
|
[This is the first released version of the Lesser GPL. It also counts |
||||
|
as the successor of the GNU Library Public License, version 2, hence |
||||
|
the version number 2.1.] |
||||
|
|
||||
|
Preamble |
||||
|
|
||||
|
The licenses for most software are designed to take away your |
||||
|
freedom to share and change it. By contrast, the GNU General Public |
||||
|
Licenses are intended to guarantee your freedom to share and change |
||||
|
free software--to make sure the software is free for all its users. |
||||
|
|
||||
|
This license, the Lesser General Public License, applies to some |
||||
|
specially designated software packages--typically libraries--of the |
||||
|
Free Software Foundation and other authors who decide to use it. You |
||||
|
can use it too, but we suggest you first think carefully about whether |
||||
|
this license or the ordinary General Public License is the better |
||||
|
strategy to use in any particular case, based on the explanations below. |
||||
|
|
||||
|
When we speak of free software, we are referring to freedom of use, |
||||
|
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 this service if you wish); that you receive source code or can get |
||||
|
it if you want it; that you can change the software and use pieces of |
||||
|
it in new free programs; and that you are informed that you can do |
||||
|
these things. |
||||
|
|
||||
|
To protect your rights, we need to make restrictions that forbid |
||||
|
distributors to deny you these rights or to ask you to surrender these |
||||
|
rights. These restrictions translate to certain responsibilities for |
||||
|
you if you distribute copies of the library or if you modify it. |
||||
|
|
||||
|
For example, if you distribute copies of the library, whether gratis |
||||
|
or for a fee, you must give the recipients all the rights that we gave |
||||
|
you. You must make sure that they, too, receive or can get the source |
||||
|
code. If you link other code with the library, you must provide |
||||
|
complete object files to the recipients, so that they can relink them |
||||
|
with the library after making changes to the library and recompiling |
||||
|
it. And you must show them these terms so they know their rights. |
||||
|
|
||||
|
We protect your rights with a two-step method: (1) we copyright the |
||||
|
library, and (2) we offer you this license, which gives you legal |
||||
|
permission to copy, distribute and/or modify the library. |
||||
|
|
||||
|
To protect each distributor, we want to make it very clear that |
||||
|
there is no warranty for the free library. Also, if the library is |
||||
|
modified by someone else and passed on, the recipients should know |
||||
|
that what they have is not the original version, so that the original |
||||
|
author's reputation will not be affected by problems that might be |
||||
|
introduced by others. |
||||
|
|
||||
|
Finally, software patents pose a constant threat to the existence of |
||||
|
any free program. We wish to make sure that a company cannot |
||||
|
effectively restrict the users of a free program by obtaining a |
||||
|
restrictive license from a patent holder. Therefore, we insist that |
||||
|
any patent license obtained for a version of the library must be |
||||
|
consistent with the full freedom of use specified in this license. |
||||
|
|
||||
|
Most GNU software, including some libraries, is covered by the |
||||
|
ordinary GNU General Public License. This license, the GNU Lesser |
||||
|
General Public License, applies to certain designated libraries, and |
||||
|
is quite different from the ordinary General Public License. We use |
||||
|
this license for certain libraries in order to permit linking those |
||||
|
libraries into non-free programs. |
||||
|
|
||||
|
When a program is linked with a library, whether statically or using |
||||
|
a shared library, the combination of the two is legally speaking a |
||||
|
combined work, a derivative of the original library. The ordinary |
||||
|
General Public License therefore permits such linking only if the |
||||
|
entire combination fits its criteria of freedom. The Lesser General |
||||
|
Public License permits more lax criteria for linking other code with |
||||
|
the library. |
||||
|
|
||||
|
We call this license the "Lesser" General Public License because it |
||||
|
does Less to protect the user's freedom than the ordinary General |
||||
|
Public License. It also provides other free software developers Less |
||||
|
of an advantage over competing non-free programs. These disadvantages |
||||
|
are the reason we use the ordinary General Public License for many |
||||
|
libraries. However, the Lesser license provides advantages in certain |
||||
|
special circumstances. |
||||
|
|
||||
|
For example, on rare occasions, there may be a special need to |
||||
|
encourage the widest possible use of a certain library, so that it becomes |
||||
|
a de-facto standard. To achieve this, non-free programs must be |
||||
|
allowed to use the library. A more frequent case is that a free |
||||
|
library does the same job as widely used non-free libraries. In this |
||||
|
case, there is little to gain by limiting the free library to free |
||||
|
software only, so we use the Lesser General Public License. |
||||
|
|
||||
|
In other cases, permission to use a particular library in non-free |
||||
|
programs enables a greater number of people to use a large body of |
||||
|
free software. For example, permission to use the GNU C Library in |
||||
|
non-free programs enables many more people to use the whole GNU |
||||
|
operating system, as well as its variant, the GNU/Linux operating |
||||
|
system. |
||||
|
|
||||
|
Although the Lesser General Public License is Less protective of the |
||||
|
users' freedom, it does ensure that the user of a program that is |
||||
|
linked with the Library has the freedom and the wherewithal to run |
||||
|
that program using a modified version of the Library. |
||||
|
|
||||
|
The precise terms and conditions for copying, distribution and |
||||
|
modification follow. Pay close attention to the difference between a |
||||
|
"work based on the library" and a "work that uses the library". The |
||||
|
former contains code derived from the library, whereas the latter must |
||||
|
be combined with the library in order to run. |
||||
|
|
||||
|
GNU LESSER GENERAL PUBLIC LICENSE |
||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |
||||
|
|
||||
|
0. This License Agreement applies to any software library or other |
||||
|
program which contains a notice placed by the copyright holder or |
||||
|
other authorized party saying it may be distributed under the terms of |
||||
|
this Lesser General Public License (also called "this License"). |
||||
|
Each licensee is addressed as "you". |
||||
|
|
||||
|
A "library" means a collection of software functions and/or data |
||||
|
prepared so as to be conveniently linked with application programs |
||||
|
(which use some of those functions and data) to form executables. |
||||
|
|
||||
|
The "Library", below, refers to any such software library or work |
||||
|
which has been distributed under these terms. A "work based on the |
||||
|
Library" means either the Library or any derivative work under |
||||
|
copyright law: that is to say, a work containing the Library or a |
||||
|
portion of it, either verbatim or with modifications and/or translated |
||||
|
straightforwardly into another language. (Hereinafter, translation is |
||||
|
included without limitation in the term "modification".) |
||||
|
|
||||
|
"Source code" for a work means the preferred form of the work for |
||||
|
making modifications to it. For a library, complete source code means |
||||
|
all the source code for all modules it contains, plus any associated |
||||
|
interface definition files, plus the scripts used to control compilation |
||||
|
and installation of the library. |
||||
|
|
||||
|
Activities other than copying, distribution and modification are not |
||||
|
covered by this License; they are outside its scope. The act of |
||||
|
running a program using the Library is not restricted, and output from |
||||
|
such a program is covered only if its contents constitute a work based |
||||
|
on the Library (independent of the use of the Library in a tool for |
||||
|
writing it). Whether that is true depends on what the Library does |
||||
|
and what the program that uses the Library does. |
||||
|
|
||||
|
1. You may copy and distribute verbatim copies of the Library's |
||||
|
complete source code as you receive it, in any medium, provided that |
||||
|
you conspicuously and appropriately publish on each copy an |
||||
|
appropriate copyright notice and disclaimer of warranty; keep intact |
||||
|
all the notices that refer to this License and to the absence of any |
||||
|
warranty; and distribute a copy of this License along with the |
||||
|
Library. |
||||
|
|
||||
|
You may charge a fee for the physical act of transferring a copy, |
||||
|
and you may at your option offer warranty protection in exchange for a |
||||
|
fee. |
||||
|
|
||||
|
2. You may modify your copy or copies of the Library or any portion |
||||
|
of it, thus forming a work based on the Library, and copy and |
||||
|
distribute such modifications or work under the terms of Section 1 |
||||
|
above, provided that you also meet all of these conditions: |
||||
|
|
||||
|
a) The modified work must itself be a software library. |
||||
|
|
||||
|
b) You must cause the files modified to carry prominent notices |
||||
|
stating that you changed the files and the date of any change. |
||||
|
|
||||
|
c) You must cause the whole of the work to be licensed at no |
||||
|
charge to all third parties under the terms of this License. |
||||
|
|
||||
|
d) If a facility in the modified Library refers to a function or a |
||||
|
table of data to be supplied by an application program that uses |
||||
|
the facility, other than as an argument passed when the facility |
||||
|
is invoked, then you must make a good faith effort to ensure that, |
||||
|
in the event an application does not supply such function or |
||||
|
table, the facility still operates, and performs whatever part of |
||||
|
its purpose remains meaningful. |
||||
|
|
||||
|
(For example, a function in a library to compute square roots has |
||||
|
a purpose that is entirely well-defined independent of the |
||||
|
application. Therefore, Subsection 2d requires that any |
||||
|
application-supplied function or table used by this function must |
||||
|
be optional: if the application does not supply it, the square |
||||
|
root function must still compute square roots.) |
||||
|
|
||||
|
These requirements apply to the modified work as a whole. If |
||||
|
identifiable sections of that work are not derived from the Library, |
||||
|
and can be reasonably considered independent and separate works in |
||||
|
themselves, then this License, and its terms, do not apply to those |
||||
|
sections when you distribute them as separate works. But when you |
||||
|
distribute the same sections as part of a whole which is a work based |
||||
|
on the Library, the distribution of the whole must be on the terms of |
||||
|
this License, whose permissions for other licensees extend to the |
||||
|
entire whole, and thus to each and every part regardless of who wrote |
||||
|
it. |
||||
|
|
||||
|
Thus, it is not the intent of this section to claim rights or contest |
||||
|
your rights to work written entirely by you; rather, the intent is to |
||||
|
exercise the right to control the distribution of derivative or |
||||
|
collective works based on the Library. |
||||
|
|
||||
|
In addition, mere aggregation of another work not based on the Library |
||||
|
with the Library (or with a work based on the Library) on a volume of |
||||
|
a storage or distribution medium does not bring the other work under |
||||
|
the scope of this License. |
||||
|
|
||||
|
3. You may opt to apply the terms of the ordinary GNU General Public |
||||
|
License instead of this License to a given copy of the Library. To do |
||||
|
this, you must alter all the notices that refer to this License, so |
||||
|
that they refer to the ordinary GNU General Public License, version 2, |
||||
|
instead of to this License. (If a newer version than version 2 of the |
||||
|
ordinary GNU General Public License has appeared, then you can specify |
||||
|
that version instead if you wish.) Do not make any other change in |
||||
|
these notices. |
||||
|
|
||||
|
Once this change is made in a given copy, it is irreversible for |
||||
|
that copy, so the ordinary GNU General Public License applies to all |
||||
|
subsequent copies and derivative works made from that copy. |
||||
|
|
||||
|
This option is useful when you wish to copy part of the code of |
||||
|
the Library into a program that is not a library. |
||||
|
|
||||
|
4. You may copy and distribute the Library (or a portion or |
||||
|
derivative of it, under Section 2) in object code or executable form |
||||
|
under the terms of Sections 1 and 2 above provided that you accompany |
||||
|
it with the complete corresponding machine-readable source code, which |
||||
|
must be distributed under the terms of Sections 1 and 2 above on a |
||||
|
medium customarily used for software interchange. |
||||
|
|
||||
|
If distribution of object code is made by offering access to copy |
||||
|
from a designated place, then offering equivalent access to copy the |
||||
|
source code from the same place satisfies the requirement to |
||||
|
distribute the source code, even though third parties are not |
||||
|
compelled to copy the source along with the object code. |
||||
|
|
||||
|
5. A program that contains no derivative of any portion of the |
||||
|
Library, but is designed to work with the Library by being compiled or |
||||
|
linked with it, is called a "work that uses the Library". Such a |
||||
|
work, in isolation, is not a derivative work of the Library, and |
||||
|
therefore falls outside the scope of this License. |
||||
|
|
||||
|
However, linking a "work that uses the Library" with the Library |
||||
|
creates an executable that is a derivative of the Library (because it |
||||
|
contains portions of the Library), rather than a "work that uses the |
||||
|
library". The executable is therefore covered by this License. |
||||
|
Section 6 states terms for distribution of such executables. |
||||
|
|
||||
|
When a "work that uses the Library" uses material from a header file |
||||
|
that is part of the Library, the object code for the work may be a |
||||
|
derivative work of the Library even though the source code is not. |
||||
|
Whether this is true is especially significant if the work can be |
||||
|
linked without the Library, or if the work is itself a library. The |
||||
|
threshold for this to be true is not precisely defined by law. |
||||
|
|
||||
|
If such an object file uses only numerical parameters, data |
||||
|
structure layouts and accessors, and small macros and small inline |
||||
|
functions (ten lines or less in length), then the use of the object |
||||
|
file is unrestricted, regardless of whether it is legally a derivative |
||||
|
work. (Executables containing this object code plus portions of the |
||||
|
Library will still fall under Section 6.) |
||||
|
|
||||
|
Otherwise, if the work is a derivative of the Library, you may |
||||
|
distribute the object code for the work under the terms of Section 6. |
||||
|
Any executables containing that work also fall under Section 6, |
||||
|
whether or not they are linked directly with the Library itself. |
||||
|
|
||||
|
6. As an exception to the Sections above, you may also combine or |
||||
|
link a "work that uses the Library" with the Library to produce a |
||||
|
work containing portions of the Library, and distribute that work |
||||
|
under terms of your choice, provided that the terms permit |
||||
|
modification of the work for the customer's own use and reverse |
||||
|
engineering for debugging such modifications. |
||||
|
|
||||
|
You must give prominent notice with each copy of the work that the |
||||
|
Library is used in it and that the Library and its use are covered by |
||||
|
this License. You must supply a copy of this License. If the work |
||||
|
during execution displays copyright notices, you must include the |
||||
|
copyright notice for the Library among them, as well as a reference |
||||
|
directing the user to the copy of this License. Also, you must do one |
||||
|
of these things: |
||||
|
|
||||
|
a) Accompany the work with the complete corresponding |
||||
|
machine-readable source code for the Library including whatever |
||||
|
changes were used in the work (which must be distributed under |
||||
|
Sections 1 and 2 above); and, if the work is an executable linked |
||||
|
with the Library, with the complete machine-readable "work that |
||||
|
uses the Library", as object code and/or source code, so that the |
||||
|
user can modify the Library and then relink to produce a modified |
||||
|
executable containing the modified Library. (It is understood |
||||
|
that the user who changes the contents of definitions files in the |
||||
|
Library will not necessarily be able to recompile the application |
||||
|
to use the modified definitions.) |
||||
|
|
||||
|
b) Use a suitable shared library mechanism for linking with the |
||||
|
Library. A suitable mechanism is one that (1) uses at run time a |
||||
|
copy of the library already present on the user's computer system, |
||||
|
rather than copying library functions into the executable, and (2) |
||||
|
will operate properly with a modified version of the library, if |
||||
|
the user installs one, as long as the modified version is |
||||
|
interface-compatible with the version that the work was made with. |
||||
|
|
||||
|
c) Accompany the work with a written offer, valid for at |
||||
|
least three years, to give the same user the materials |
||||
|
specified in Subsection 6a, above, for a charge no more |
||||
|
than the cost of performing this distribution. |
||||
|
|
||||
|
d) If distribution of the work is made by offering access to copy |
||||
|
from a designated place, offer equivalent access to copy the above |
||||
|
specified materials from the same place. |
||||
|
|
||||
|
e) Verify that the user has already received a copy of these |
||||
|
materials or that you have already sent this user a copy. |
||||
|
|
||||
|
For an executable, the required form of the "work that uses the |
||||
|
Library" must include any data and utility programs needed for |
||||
|
reproducing the executable from it. However, as a special exception, |
||||
|
the materials to be distributed need not include anything that is |
||||
|
normally distributed (in either source or binary form) with the major |
||||
|
components (compiler, kernel, and so on) of the operating system on |
||||
|
which the executable runs, unless that component itself accompanies |
||||
|
the executable. |
||||
|
|
||||
|
It may happen that this requirement contradicts the license |
||||
|
restrictions of other proprietary libraries that do not normally |
||||
|
accompany the operating system. Such a contradiction means you cannot |
||||
|
use both them and the Library together in an executable that you |
||||
|
distribute. |
||||
|
|
||||
|
7. You may place library facilities that are a work based on the |
||||
|
Library side-by-side in a single library together with other library |
||||
|
facilities not covered by this License, and distribute such a combined |
||||
|
library, provided that the separate distribution of the work based on |
||||
|
the Library and of the other library facilities is otherwise |
||||
|
permitted, and provided that you do these two things: |
||||
|
|
||||
|
a) Accompany the combined library with a copy of the same work |
||||
|
based on the Library, uncombined with any other library |
||||
|
facilities. This must be distributed under the terms of the |
||||
|
Sections above. |
||||
|
|
||||
|
b) Give prominent notice with the combined library of the fact |
||||
|
that part of it is a work based on the Library, and explaining |
||||
|
where to find the accompanying uncombined form of the same work. |
||||
|
|
||||
|
8. You may not copy, modify, sublicense, link with, or distribute |
||||
|
the Library except as expressly provided under this License. Any |
||||
|
attempt otherwise to copy, modify, sublicense, link with, or |
||||
|
distribute the Library is void, and will automatically terminate your |
||||
|
rights under this License. However, parties who have received copies, |
||||
|
or rights, from you under this License will not have their licenses |
||||
|
terminated so long as such parties remain in full compliance. |
||||
|
|
||||
|
9. You are not required to accept this License, since you have not |
||||
|
signed it. However, nothing else grants you permission to modify or |
||||
|
distribute the Library or its derivative works. These actions are |
||||
|
prohibited by law if you do not accept this License. Therefore, by |
||||
|
modifying or distributing the Library (or any work based on the |
||||
|
Library), you indicate your acceptance of this License to do so, and |
||||
|
all its terms and conditions for copying, distributing or modifying |
||||
|
the Library or works based on it. |
||||
|
|
||||
|
10. Each time you redistribute the Library (or any work based on the |
||||
|
Library), the recipient automatically receives a license from the |
||||
|
original licensor to copy, distribute, link with or modify the Library |
||||
|
subject to these terms and conditions. You may not impose any further |
||||
|
restrictions on the recipients' exercise of the rights granted herein. |
||||
|
You are not responsible for enforcing compliance by third parties with |
||||
|
this License. |
||||
|
|
||||
|
11. If, as a consequence of a court judgment or allegation of patent |
||||
|
infringement or for any other reason (not limited to patent issues), |
||||
|
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 |
||||
|
distribute so as to satisfy simultaneously your obligations under this |
||||
|
License and any other pertinent obligations, then as a consequence you |
||||
|
may not distribute the Library at all. For example, if a patent |
||||
|
license would not permit royalty-free redistribution of the Library by |
||||
|
all those who receive copies directly or indirectly through you, then |
||||
|
the only way you could satisfy both it and this License would be to |
||||
|
refrain entirely from distribution of the Library. |
||||
|
|
||||
|
If any portion of this section is held invalid or unenforceable under any |
||||
|
particular circumstance, the balance of the section is intended to apply, |
||||
|
and the section as a whole is intended to apply in other circumstances. |
||||
|
|
||||
|
It is not the purpose of this section to induce you to infringe any |
||||
|
patents or other property right claims or to contest validity of any |
||||
|
such claims; this section has the sole purpose of protecting the |
||||
|
integrity of the free software distribution system which is |
||||
|
implemented by public license practices. Many people have made |
||||
|
generous contributions to the wide range of software distributed |
||||
|
through that system in reliance on consistent application of that |
||||
|
system; it is up to the author/donor to decide if he or she is willing |
||||
|
to distribute software through any other system and a licensee cannot |
||||
|
impose that choice. |
||||
|
|
||||
|
This section is intended to make thoroughly clear what is believed to |
||||
|
be a consequence of the rest of this License. |
||||
|
|
||||
|
12. If the distribution and/or use of the Library is restricted in |
||||
|
certain countries either by patents or by copyrighted interfaces, the |
||||
|
original copyright holder who places the Library under this License may add |
||||
|
an explicit geographical distribution limitation excluding those countries, |
||||
|
so that distribution is permitted only in or among countries not thus |
||||
|
excluded. In such case, this License incorporates the limitation as if |
||||
|
written in the body of this License. |
||||
|
|
||||
|
13. The Free Software Foundation may publish revised and/or new |
||||
|
versions of the Lesser 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 Library |
||||
|
specifies a version number of this License which applies to it and |
||||
|
"any later version", you have the option of following the terms and |
||||
|
conditions either of that version or of any later version published by |
||||
|
the Free Software Foundation. If the Library does not specify a |
||||
|
license version number, you may choose any version ever published by |
||||
|
the Free Software Foundation. |
||||
|
|
||||
|
14. If you wish to incorporate parts of the Library into other free |
||||
|
programs whose distribution conditions are incompatible with these, |
||||
|
write to the author to ask for permission. For software which is |
||||
|
copyrighted by the Free Software Foundation, write to the Free |
||||
|
Software Foundation; we sometimes make exceptions for this. Our |
||||
|
decision will be guided by the two goals of preserving the free status |
||||
|
of all derivatives of our free software and of promoting the sharing |
||||
|
and reuse of software generally. |
||||
|
|
||||
|
NO WARRANTY |
||||
|
|
||||
|
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO |
||||
|
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. |
||||
|
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR |
||||
|
OTHER PARTIES PROVIDE THE LIBRARY "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 |
||||
|
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME |
||||
|
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. |
||||
|
|
||||
|
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN |
||||
|
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY |
||||
|
AND/OR REDISTRIBUTE THE LIBRARY 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 |
||||
|
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF |
||||
|
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
||||
|
DAMAGES. |
||||
|
|
||||
|
END OF TERMS AND CONDITIONS |
||||
|
|
||||
|
How to Apply These Terms to Your New Libraries |
||||
|
|
||||
|
If you develop a new library, and you want it to be of the greatest |
||||
|
possible use to the public, we recommend making it free software that |
||||
|
everyone can redistribute and change. You can do so by permitting |
||||
|
redistribution under these terms (or, alternatively, under the terms of the |
||||
|
ordinary General Public License). |
||||
|
|
||||
|
To apply these terms, attach the following notices to the library. It is |
||||
|
safest to attach them to the start of each source file to most effectively |
||||
|
convey 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 library's name and a brief idea of what it does.> |
||||
|
Copyright (C) <year> <name of author> |
||||
|
|
||||
|
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.1 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, write to the Free Software |
||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
|
||||
|
Also add information on how to contact you by electronic and paper mail. |
||||
|
|
||||
|
You should also get your employer (if you work as a programmer) or your |
||||
|
school, if any, to sign a "copyright disclaimer" for the library, if |
||||
|
necessary. Here is a sample; alter the names: |
||||
|
|
||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the |
||||
|
library `Frob' (a library for tweaking knobs) written by James Random Hacker. |
||||
|
|
||||
|
<signature of Ty Coon>, 1 April 1990 |
||||
|
Ty Coon, President of Vice |
||||
|
|
||||
|
That's all there is to it! |
||||
|
|
||||
|
|
@ -0,0 +1,196 @@ |
|||||
|
#! /usr/bin/make -rf
|
||||
|
# $Id: Makefile.in,v 1.11 2007/01/15 21:19:08 mjt Exp $
|
||||
|
# libudns Makefile
|
||||
|
#
|
||||
|
# Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru>
|
||||
|
# This file is part of UDNS library, an async DNS stub resolver.
|
||||
|
#
|
||||
|
# 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.1 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, in file named COPYING.LGPL; if not,
|
||||
|
# write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
|
# Suite 330, Boston, MA 02111-1307 USA
|
||||
|
|
||||
|
NAME = udns |
||||
|
VERS = 0.0.9 |
||||
|
SRCS = udns_dn.c udns_dntosp.c udns_parse.c udns_resolver.c udns_init.c \
|
||||
|
udns_misc.c udns_XtoX.c \
|
||||
|
udns_rr_a.c udns_rr_ptr.c udns_rr_mx.c udns_rr_txt.c udns_bl.c \
|
||||
|
udns_rr_srv.c udns_rr_naptr.c udns_codes.c |
||||
|
USRCS = dnsget.c rblcheck.c ex-rdns.c |
||||
|
DEB = debian/copyright debian/changelog debian/control debian/rules |
||||
|
DIST = COPYING.LGPL udns.h udns.3 dnsget.1 rblcheck.1 $(SRCS) $(USRCS) \
|
||||
|
NEWS TODO NOTES Makefile.in configure configure.lib \
|
||||
|
inet_XtoX.c getopt.c |
||||
|
|
||||
|
OBJS = $(SRCS:.c=.o) $(GEN:.c=.o) |
||||
|
LIB = lib$(NAME).a |
||||
|
LIBFL = -L. -l$(NAME) |
||||
|
|
||||
|
SOVER = 0 |
||||
|
SOBJS = $(OBJS:.o=.lo) |
||||
|
SOLIB = lib$(NAME)_s.so |
||||
|
SOLIBV = lib$(NAME).so.$(SOVER) |
||||
|
SOLIBFL= -L. -l$(NAME)_s |
||||
|
|
||||
|
LIBS = $(LIB) $(SOLIBV) |
||||
|
|
||||
|
UTILS = $(USRCS:.c=) |
||||
|
UOBJS = $(USRCS:.c=.o) |
||||
|
SOUTILS = $(USRCS:.c=_s) |
||||
|
|
||||
|
NAMEPFX = $(NAME)-$(VERS) |
||||
|
|
||||
|
CC = @CC@ |
||||
|
CFLAGS = @CFLAGS@ |
||||
|
CDEFS = @CDEFS@ |
||||
|
PICFLAGS = -fPIC |
||||
|
AWK = awk |
||||
|
|
||||
|
all: static |
||||
|
|
||||
|
.SUFFIXES: .c .o .lo |
||||
|
|
||||
|
static: $(LIB) $(UTILS) |
||||
|
staticlib: $(LIB) |
||||
|
$(LIB): $(OBJS) |
||||
|
-rm -f $@ |
||||
|
$(AR) rv $@ $(OBJS) |
||||
|
.c.o: |
||||
|
$(CC) $(CFLAGS) $(CDEFS) -c $< |
||||
|
|
||||
|
shared: $(SOLIBV) $(SOUTILS) |
||||
|
sharedlib: $(SOLIBV) |
||||
|
|
||||
|
$(SOLIBV): $(SOBJS) |
||||
|
$(CC) -shared -Wl,--soname,$(SOLIBV) -o $@ $(SOBJS) |
||||
|
$(SOLIB): $(SOLIBV) |
||||
|
rm -f $@ |
||||
|
ln -s $(SOLIBV) $@ |
||||
|
.c.lo: |
||||
|
$(CC) $(CFLAGS) $(PICFLAGS) $(CDEFS) -o $@ -c $< |
||||
|
|
||||
|
# udns_codes.c is generated from udns.h
|
||||
|
udns_codes.c: udns.h |
||||
|
@echo Generating $@ |
||||
|
@set -e; exec >$@.tmp; \
|
||||
|
set T type C class R rcode; \
|
||||
|
echo "/* Automatically generated. */"; \
|
||||
|
echo "#include \"udns.h\""; \
|
||||
|
while [ "$$1" ]; do \
|
||||
|
echo; \
|
||||
|
echo "const struct dns_nameval dns_$${2}tab[] = {"; \
|
||||
|
$(AWK) "/^ DNS_$${1}_[A-Z0-9_]+[ ]*=/ \
|
||||
|
{ printf \" {%s,\\\"%s\\\"},\\n\", \$$1, substr(\$$1,7) }" \
|
||||
|
udns.h ; \
|
||||
|
echo " {0,0}};"; \
|
||||
|
echo "const char *dns_$${2}name(enum dns_$${2} code) {"; \
|
||||
|
echo " static char nm[20];"; \
|
||||
|
echo " switch(code) {"; \
|
||||
|
$(AWK) "BEGIN{i=0} \
|
||||
|
/^ DNS_$${1}_[A-Z0-9_]+[ ]*=/ \
|
||||
|
{printf \" case %s: return dns_$${2}tab[%d].name;\\n\",\$$1,i++}\
|
||||
|
" udns.h ; \
|
||||
|
echo " }"; \
|
||||
|
echo " return _dns_format_code(nm,\"$$2\",code);"; \
|
||||
|
echo "}"; \
|
||||
|
shift 2; \
|
||||
|
done |
||||
|
@mv $@.tmp $@ |
||||
|
|
||||
|
udns.3.html: udns.3 |
||||
|
groff -man -Thtml udns.3 > $@.tmp |
||||
|
mv $@.tmp $@ |
||||
|
|
||||
|
dist: $(NAMEPFX).tar.gz |
||||
|
$(NAMEPFX).tar.gz: $(DIST) $(DEB) |
||||
|
mkdir $(NAMEPFX) $(NAMEPFX)/debian |
||||
|
ln $(DIST) $(NAMEPFX) |
||||
|
ln $(DEB) $(NAMEPFX)/debian |
||||
|
tar cvfz $@ $(NAMEPFX) |
||||
|
rm -rf $(NAMEPFX) |
||||
|
subdist: |
||||
|
cp -p $(DIST) $(TARGET)/ |
||||
|
|
||||
|
clean: |
||||
|
rm -f $(OBJS) |
||||
|
rm -f $(SOBJS) |
||||
|
rm -f $(UOBJS) |
||||
|
rm -f build-stamp config.log |
||||
|
distclean: clean |
||||
|
rm -f $(LIBS) $(SOLIB) udns.3.html |
||||
|
rm -f $(UTILS) $(SOUTILS) |
||||
|
rm -f config.status config.h Makefile |
||||
|
|
||||
|
|
||||
|
Makefile: configure configure.lib Makefile.in |
||||
|
./configure |
||||
|
@echo |
||||
|
@echo Please rerun make >&2 |
||||
|
@exit 1 |
||||
|
|
||||
|
.PHONY: all static staticlib shared sharedlib dist clean distclean subdist \ |
||||
|
depend dep deps |
||||
|
|
||||
|
depend dep deps: $(SRCS) $(USRC) |
||||
|
@echo Generating deps for: |
||||
|
@echo \ $(SRCS) |
||||
|
@echo \ $(USRCS) |
||||
|
@sed '/^# depend/q' Makefile.in > Makefile.tmp |
||||
|
@set -e; \
|
||||
|
for f in $(SRCS) $(USRCS); do \
|
||||
|
echo $${f%.c}.o $${f%.c}.lo: $$f \
|
||||
|
`sed -n 's/^#[ ]*include[ ]*"\(.*\)".*/\1/p' $$f`; \
|
||||
|
done >> Makefile.tmp; \
|
||||
|
for f in $(USRCS:.c=.o); do \
|
||||
|
echo "$${f%.?}: $$f \$$(LIB)"; \
|
||||
|
echo " \$$(CC) \$$(CFLAGS) -o \$$@ $$f \$$(LIBFL)"; \
|
||||
|
echo "$${f%.?}_s: $$f \$$(SOLIB)"; \
|
||||
|
echo " \$$(CC) \$$(CFLAGS) -o \$$@ $$f \$$(SOLIBFL)"; \
|
||||
|
done >> Makefile.tmp ; \
|
||||
|
if cmp Makefile.tmp Makefile.in >/dev/null 2>&1 ; then \
|
||||
|
echo Makefile.in unchanged; rm -f Makefile.tmp; \
|
||||
|
else \
|
||||
|
echo Updating Makfile.in; mv -f Makefile.tmp Makefile.in ; \
|
||||
|
fi |
||||
|
|
||||
|
# depend
|
||||
|
udns_dn.o udns_dn.lo: udns_dn.c udns.h |
||||
|
udns_dntosp.o udns_dntosp.lo: udns_dntosp.c udns.h |
||||
|
udns_parse.o udns_parse.lo: udns_parse.c udns.h |
||||
|
udns_resolver.o udns_resolver.lo: udns_resolver.c config.h udns.h |
||||
|
udns_init.o udns_init.lo: udns_init.c config.h udns.h |
||||
|
udns_misc.o udns_misc.lo: udns_misc.c udns.h |
||||
|
udns_XtoX.o udns_XtoX.lo: udns_XtoX.c config.h udns.h inet_XtoX.c |
||||
|
udns_rr_a.o udns_rr_a.lo: udns_rr_a.c udns.h |
||||
|
udns_rr_ptr.o udns_rr_ptr.lo: udns_rr_ptr.c udns.h |
||||
|
udns_rr_mx.o udns_rr_mx.lo: udns_rr_mx.c udns.h |
||||
|
udns_rr_txt.o udns_rr_txt.lo: udns_rr_txt.c udns.h |
||||
|
udns_bl.o udns_bl.lo: udns_bl.c udns.h |
||||
|
udns_rr_srv.o udns_rr_srv.lo: udns_rr_srv.c udns.h |
||||
|
udns_rr_naptr.o udns_rr_naptr.lo: udns_rr_naptr.c udns.h |
||||
|
udns_codes.o udns_codes.lo: udns_codes.c udns.h |
||||
|
dnsget.o dnsget.lo: dnsget.c config.h udns.h getopt.c |
||||
|
rblcheck.o rblcheck.lo: rblcheck.c udns.h getopt.c |
||||
|
ex-rdns.o ex-rdns.lo: ex-rdns.c udns.h |
||||
|
dnsget: dnsget.o $(LIB) |
||||
|
$(CC) $(CFLAGS) -o $@ dnsget.o $(LIBFL) |
||||
|
dnsget_s: dnsget.o $(SOLIB) |
||||
|
$(CC) $(CFLAGS) -o $@ dnsget.o $(SOLIBFL) |
||||
|
rblcheck: rblcheck.o $(LIB) |
||||
|
$(CC) $(CFLAGS) -o $@ rblcheck.o $(LIBFL) |
||||
|
rblcheck_s: rblcheck.o $(SOLIB) |
||||
|
$(CC) $(CFLAGS) -o $@ rblcheck.o $(SOLIBFL) |
||||
|
ex-rdns: ex-rdns.o $(LIB) |
||||
|
$(CC) $(CFLAGS) -o $@ ex-rdns.o $(LIBFL) |
||||
|
ex-rdns_s: ex-rdns.o $(SOLIB) |
||||
|
$(CC) $(CFLAGS) -o $@ ex-rdns.o $(SOLIBFL) |
@ -0,0 +1,85 @@ |
|||||
|
$Id: NEWS,v 1.11 2007/01/15 21:19:08 mjt Exp $ |
||||
|
|
||||
|
User-visible changes in udns library. Recent changes on top. |
||||
|
|
||||
|
0.0.9 (16 Jan 2007) |
||||
|
|
||||
|
- incompat: minor API changes in dns_init() &friends. dns_init() |
||||
|
now requires extra `struct dns_ctx *' argument. Not bumped |
||||
|
soversion yet - I only expect one "release" with this change, |
||||
|
0.1 will have more changes and will increment so version |
||||
|
|
||||
|
- many small bugfixes, here and there |
||||
|
|
||||
|
- more robust FORMERR replies handling - not only such replies are now |
||||
|
recognized, but udns retries queries without EDNS0 extensions if tried |
||||
|
with, but server reported FORMERR |
||||
|
|
||||
|
- portability changes, udns now includes getopt() implementation fo |
||||
|
the systems lacking it (mostly windows), and dns_ntop()&dns_pton(), |
||||
|
which are either just wrappers for system functions or reimplementations. |
||||
|
|
||||
|
- build is now based on autoconf-like configuration |
||||
|
|
||||
|
- NAPTR (RFC3403) RR decoding support |
||||
|
|
||||
|
- new file NOTES which complements TODO somewhat, and includes some |
||||
|
important shortcomings |
||||
|
|
||||
|
- many internal cleanups, including some preparations for better error |
||||
|
recovery, security and robustness (and thus API changes) |
||||
|
|
||||
|
- removed some #defines which are now unused (like DNS_MAXSRCH) |
||||
|
|
||||
|
- changed WIN32 to WINDOWS everywhere in preprocessor tests, |
||||
|
to be able to build it on win64 as well |
||||
|
|
||||
|
0.0.8 (12 Sep 2005) |
||||
|
|
||||
|
- added SRV records (rfc2782) parsing, |
||||
|
thanks to Thadeu Lima de Souza Cascardo for implementation. |
||||
|
|
||||
|
- bugfixes: |
||||
|
o use uninitialized value when no reply, library died with assertion: |
||||
|
assert((status < 0 && result == 0) || (status >= 0 && result != 0)). |
||||
|
o on some OSes, struct sockaddr_in has additional fields, so |
||||
|
memcmp'ing two sockaddresses does not work. |
||||
|
|
||||
|
- rblcheck(.1) |
||||
|
|
||||
|
0.0.7 (20 Apr 2005) |
||||
|
|
||||
|
- dnsget.1 manpage and several enhancements to dnsget. |
||||
|
|
||||
|
- allow nameserver names for -n option of dnsget. |
||||
|
|
||||
|
- API change: all dns_submit*() routines now does not expect |
||||
|
last `now' argument, since requests aren't sent immediately |
||||
|
anymore. |
||||
|
|
||||
|
- API change: different application timer callback mechanism. |
||||
|
Udns now uses single per-context timer instead of per-query. |
||||
|
|
||||
|
- don't assume DNS replies only contain backward DN pointers, |
||||
|
allow forward pointers too. Change parsing API. |
||||
|
|
||||
|
- debianize |
||||
|
|
||||
|
0.0.6 (08 Apr 2005) |
||||
|
|
||||
|
- use double sorted list for requests (sorted by deadline). |
||||
|
This should significantly speed up timeout processing for |
||||
|
large number of requests. |
||||
|
|
||||
|
- changed debugging interface, so it is finally useable |
||||
|
(still not documented). |
||||
|
|
||||
|
- dnsget routine is now Officially Useable, and sometimes |
||||
|
even more useable than `host' from BIND distribution |
||||
|
(and sometimes not - dnsget does not have -C option |
||||
|
and TCP mode) |
||||
|
|
||||
|
- Debian packaging in debian/ -- udns is now maintained as a |
||||
|
native Debian package. |
||||
|
|
||||
|
- alot (and I really mean alot) of code cleanups all over. |
@ -0,0 +1,222 @@ |
|||||
|
Assorted notes about udns (library). |
||||
|
|
||||
|
UDP-only mode |
||||
|
~~~~~~~~~~~~~ |
||||
|
|
||||
|
First of all, since udns is (currently) UDP-only, there are some |
||||
|
shortcomings. |
||||
|
|
||||
|
It assumes that a reply will fit into a UDP buffer. With adoption of EDNS0, |
||||
|
and general robustness of IP stacks, in most cases it's not an issue. But |
||||
|
in some cases there may be problems: |
||||
|
|
||||
|
- if an RRset is "very large" so it does not fit even in buffer of size |
||||
|
requested by the library (current default is 4096; some servers limits |
||||
|
it further), we will not see the reply, or will only see "damaged" |
||||
|
reply (depending on the server). |
||||
|
|
||||
|
- many DNS servers ignores EDNS0 option requests. In this case, no matter |
||||
|
which buffer size udns library will request, such servers reply is limited |
||||
|
to 512 bytes (standard pre-EDNS0 DNS packet size). (Udns falls back to |
||||
|
non-EDNO0 query if EDNS0-enabled one received FORMERR or NOTIMPL error). |
||||
|
|
||||
|
The problem is that with this, udns currently will not consider replies with |
||||
|
TC (truncation) bit set, and will treat such replies the same way as it |
||||
|
treats SERVFAIL replies, thus trying next server, or temp-failing the query |
||||
|
if no more servers to try. In other words, if the reply is really large, or |
||||
|
if the servers you're using don't support EDNS0, your application will be |
||||
|
unable to resolve a given name. |
||||
|
|
||||
|
Yet it's not common situation - in practice, it's very rare. |
||||
|
|
||||
|
Implementing TCP mode isn't difficult, but it complicates API significantly. |
||||
|
Currently udns uses only single UDP socket (or - maybe in the future - two, |
||||
|
see below), but in case of TCP, it will need to open and close sockets for |
||||
|
TCP connections left and right, and that have to be integrated into an |
||||
|
application's event loop in an easy and efficient way. Plus all the |
||||
|
timeouts - different for connect(), write, and several stages of read. |
||||
|
|
||||
|
IPv6 vs IPv4 usage |
||||
|
~~~~~~~~~~~~~~~~~~ |
||||
|
|
||||
|
This is only relevant for nameservers reachable over IPv6, NOT for IPv6 |
||||
|
queries. I.e., if you've IPv6 addresses in 'nameservers' line in your |
||||
|
/etc/resolv.conf file. Even more: if you have BOTH IPv6 AND IPv4 addresses |
||||
|
there. Or pass them to udns initialization routines. |
||||
|
|
||||
|
Since udns uses a single UDP socket to communicate with all nameservers, |
||||
|
it should support both v4 and v6 communications. Most current platforms |
||||
|
supports this mode - using PF_INET6 socket and V4MAPPED addresses, i.e, |
||||
|
"tunnelling" IPv4 inside IPv6. But not all systems supports this. And |
||||
|
more, it has been said that such mode is deprecated. |
||||
|
|
||||
|
So, list only IPv4 or only IPv6 addresses, but don't mix them, in your |
||||
|
/etc/resolv.conf. |
||||
|
|
||||
|
An alternative is to use two sockets instead of 1 - one for IPv6 and one |
||||
|
for IPv4. For now I'm not sure if it's worth the complexity - again, of |
||||
|
the API, not the library itself (but this will not simplify library either). |
||||
|
|
||||
|
Single socket for all queries |
||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
||||
|
|
||||
|
Using single UDP socket for sending queries to all nameservers has obvious |
||||
|
advantages. First it's, again, trivial, simple to use API. And simple |
||||
|
library too. Also, after sending queries to all nameservers (in case first |
||||
|
didn't reply in time), we will be able to receive late reply from first |
||||
|
nameserver and accept it. |
||||
|
|
||||
|
But this mode has disadvantages too. Most important is that it's much easier |
||||
|
to send fake reply to us, as the UDP port where we expects the reply to come |
||||
|
to is constant during the whole lifetime of an application. More secure |
||||
|
implementations uses random port for every single query. While port number |
||||
|
(16 bits integer) can not hold much randomness, it's still of some help. |
||||
|
Ok, udns is a stub resolver, so it expects sorta friendly environment, but |
||||
|
on LAN it's usually much easier to fire an attack, due to the speed of local |
||||
|
network, where a bad guy can generate alot of packets in a short time. |
||||
|
|
||||
|
Choosing of DNS QueryID |
||||
|
~~~~~~~~~~~~~~~~~~~~~~~ |
||||
|
|
||||
|
Currently, udns uses sequential number for query IDs. Which simplifies |
||||
|
attacks even more (c.f. the previous item about single UDP port), making |
||||
|
them nearly trivial. The library should use random number for query ID. |
||||
|
But there's no portable way to get random numbers, even on various flavors |
||||
|
of Unix. It's possible to use low bits from tv_nsec field returned by |
||||
|
gettimeofday() (current time, nanoseconds), but I wrote the library in |
||||
|
a way to avoid making system calls where possible, because many syscalls |
||||
|
means many context switches and slow processes as a result. Maybe use some |
||||
|
application-supplied callback to get random values will be a better way, |
||||
|
defaulting to gettimeofday() method. |
||||
|
|
||||
|
Note that a single query - even if (re)sent to different nameservers, several |
||||
|
times (due to no reply received in time), uses the same qID assigned when it |
||||
|
was first dispatched. So we have: single UDP socket (fixed port number), |
||||
|
sequential (= trivially predictable) qIDs, and long lifetime of those qIDs. |
||||
|
This all makes (local) attacks against the library really trivial. |
||||
|
|
||||
|
See also comments in udns_resolver.c, udns_newid(). |
||||
|
|
||||
|
And note that at least some other stub resolvers out there (like c-ares |
||||
|
for example) also uses sequential qID. |
||||
|
|
||||
|
Assumptions about RRs returned |
||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
||||
|
|
||||
|
Currently udns processes records in the reply it received sequentially. |
||||
|
This means that order of the records is significant. For example, if |
||||
|
we asked for foo.bar A, but the server returned that foo.bar is a CNAME |
||||
|
(alias) for bar.baz, and bar.baz, in turn, has address 1.2.3.4, when |
||||
|
the CNAME should come first in reply, followed by A. While DNS specs |
||||
|
does not say anything about order of records - it's an rrSET - unordered, - |
||||
|
I think an implementation which returns the records in "wrong" order is |
||||
|
somewhat insane... |
||||
|
|
||||
|
CNAME recursion |
||||
|
~~~~~~~~~~~~~~~ |
||||
|
|
||||
|
Another interesting point is the handling of CNAMEs returned as replies |
||||
|
to non-CNAME queries. If we asked for foo.bar A, but it's a CNAME, udns |
||||
|
expects BOTH the CNAME itself and the target DN to be present in the reply. |
||||
|
In other words, udns DOES NOT RECURSE CNAMES. If we asked for foo.bar A, |
||||
|
but only record in reply was that foo.bar is a CNAME for bar.baz, udns will |
||||
|
return no records to an application (NXDOMAIN). Strictly speaking, udns |
||||
|
should repeat the query asking for bar.baz A, and recurse. But since it's |
||||
|
stub resolver, recursive resolver should recurse for us instead. |
||||
|
|
||||
|
It's not very difficult to implement, however. Probably with some (global?) |
||||
|
flag to en/dis-able the feature. Provided there's some demand for it. |
||||
|
|
||||
|
To clarify: udns handles CNAME recursion in a single reply packet just fine. |
||||
|
|
||||
|
Note also that standard gethostbyname() routine does not recurse in this |
||||
|
situation, too. |
||||
|
|
||||
|
Error reporting |
||||
|
~~~~~~~~~~~~~~~ |
||||
|
|
||||
|
Too many places in the code (various failure paths) sets generic "TEMPFAIL" |
||||
|
error condition. For example, if no nameserver replied to our query, an |
||||
|
application will get generic TEMPFAIL, instead of something like TIMEDOUT. |
||||
|
This probably should be fixed, but most applications don't care about the |
||||
|
exact reasons of failure - 4 common cases are already too much: |
||||
|
- query returned some valid data |
||||
|
- NXDOMAIN |
||||
|
- valid domain but no data of requested type - =NXDOMAIN in most cases |
||||
|
- temporary error - this one sometimes (incorrectly!) treated as NXDOMAIN |
||||
|
by (naive) applications. |
||||
|
DNS isn't yes/no, it's at least 3 variants, temp err being the 3rd important |
||||
|
case! And adding more variations for the temp error case is complicating things |
||||
|
even more - again, from an application writer standpoint. For diagnostics, |
||||
|
such more specific error cases are of good help. |
||||
|
|
||||
|
Planned API changes |
||||
|
~~~~~~~~~~~~~~~~~~~ |
||||
|
|
||||
|
At least one thing I want to change for 0.1 version is a way how queries are |
||||
|
submitted and how replies are handled. |
||||
|
|
||||
|
I want to made dns_query object to be owned by an application. So that instead |
||||
|
of udns library allocating it for the lifetime of query, it will be pre- |
||||
|
allocated by an application. This simplifies and enhances query submitting |
||||
|
interface, and complicates it a bit too, in simplest cases. |
||||
|
|
||||
|
Currently, we have: |
||||
|
|
||||
|
dns_submit_dn(dn, cls, typ, flags, parse, cbck, data) |
||||
|
dns_submit_p(name, cls, typ, flags, parse, cbck, data) |
||||
|
dns_submit_a4(ctx, name, flags, cbck, data) |
||||
|
|
||||
|
and so on -- with many parameters missed for type-specific cases, but generic |
||||
|
cases being too complex for most common usage. |
||||
|
|
||||
|
Instead, with dns_query being owned by an app, we will be able to separately |
||||
|
set up various parts of the query - domain name (various forms), type&class, |
||||
|
parser, flags, callback... and even change them at runtime. And we will also |
||||
|
be able to reuse query structures, instead of allocating/freeing them every |
||||
|
time. So the whole thing will look something like: |
||||
|
|
||||
|
q = dns_alloc_query(); |
||||
|
dns_submit(dns_q_flags(dns_q_a4(q, name, cbck), DNS_F_NOSRCH), data); |
||||
|
|
||||
|
The idea is to have a set of functions accepting struct dns_query* and |
||||
|
returning it (so the calls can be "nested" like the above), to set up |
||||
|
relevant parts of the query - specific type of callback, conversion from |
||||
|
(type-specific) query parameters into a domain name (this is for type- |
||||
|
specific query initializers), and setting various flags and options and |
||||
|
type&class things. |
||||
|
|
||||
|
One example where this is almost essential - if we want to support |
||||
|
per-query set of nameservers (which isn't at all useless: imagine a |
||||
|
high-volume mail server, were we want to direct DNSBL queries to a separate |
||||
|
set of nameservers, and rDNS queries to their own set and so on). Adding |
||||
|
another argument (set of nameservers to use) to EVERY query submitting |
||||
|
routine is.. insane. Especially since in 99% cases it will be set to |
||||
|
default NULL. But with such "nesting" of query initializers, it becomes |
||||
|
trivial. |
||||
|
|
||||
|
Another way to do the same is to manipulate query object right after a |
||||
|
query has been submitted, but before any events processing (during this |
||||
|
time, query object is allocated and initialized, but no actual network |
||||
|
packets were sent - it will happen on the next event processing). But |
||||
|
this way it become impossible to perform syncronous resolver calls, since |
||||
|
those calls hide query objects they use internally. |
||||
|
|
||||
|
Speaking of replies handling - the planned change is to stop using dynamic |
||||
|
memory (malloc) inside the library. That is, instead of allocating a buffer |
||||
|
for a reply dynamically in a parsing routine (or memdup'ing the raw reply |
||||
|
packet if no parsing routine is specified), I want udns to return the packet |
||||
|
buffer it uses internally, and change parsing routines to expect a buffer |
||||
|
for result. When parsing, a routine will return true amount of memory it |
||||
|
will need to place the result, regardless of whenever it has enough room |
||||
|
or not, so that an application can (re)allocate properly sized buffer and |
||||
|
call a parsing routine again. |
||||
|
|
||||
|
Another modification I plan to include is to have an ability to work in |
||||
|
terms of domain names (DNs) as used with on-wire DNS packets, not only |
||||
|
with asciiz representations of them. For this to work, the above two |
||||
|
changes (query submission and result passing) have to be completed first |
||||
|
(esp. the query submission part), so that it will be possible to specify |
||||
|
some additional query flags (for example) to request domain names instead |
||||
|
of the text strings, and to allow easy query submissions with either DNs |
||||
|
or text strings. |
@ -0,0 +1,69 @@ |
|||||
|
$Id: TODO,v 1.13 2007/01/15 21:19:08 mjt Exp $ |
||||
|
|
||||
|
The following is mostly an internal, not user-visible stuff. |
||||
|
|
||||
|
* rearrange an API to make dns_query object owned by application, |
||||
|
so that it'll look like this: |
||||
|
struct dns_query *q; |
||||
|
q = udns_query_alloc(ctx); |
||||
|
udns_query_set(q, options, domain_name, flags, ...); |
||||
|
udns_query_submit(ctx, q); |
||||
|
or |
||||
|
udns_query_resolve(ctx, q); |
||||
|
|
||||
|
* allow NULL callbacks? Or provide separate resolver |
||||
|
context list of queries which are done but wich did not |
||||
|
have callback, and dns_pick() routine to retrieve results |
||||
|
from this query, i.e. allow non-callback usage? The |
||||
|
non-callback usage may be handy sometimes (any *good* |
||||
|
example?), but it will be difficult to provide type-safe |
||||
|
non-callback interface due to various RR-specific types |
||||
|
in use. |
||||
|
|
||||
|
* DNS_OPT_FLAGS should be DNS_OPT_ADDFLAGS and DNS_OPT_SETFLAGS. |
||||
|
Currently one can't add a single flag bit but preserve |
||||
|
existing bits... at least not without retrieving all current |
||||
|
flags before, which isn't that bad anyway. |
||||
|
|
||||
|
* dns_set_opts() may process flags too (such as aaonly etc) |
||||
|
|
||||
|
* a way to disable $NSCACHEIP et al processing? |
||||
|
(with now separate dns_init() and dns_reset(), it has finer |
||||
|
control, but still no way to init from system files but ignore |
||||
|
environment variables and the like) |
||||
|
|
||||
|
* initialize/open the context automatically, and be more |
||||
|
liberal about initialization in general? |
||||
|
|
||||
|
* dns_init(ctx, do_open) - make the parameter opposite, aka |
||||
|
dns_init(ctx, skip_open) ? |
||||
|
|
||||
|
* allow TCP queue? |
||||
|
|
||||
|
* And oh, qID should really be random. Or... not. |
||||
|
See notes in udns_resolver.c, dns_newid(). |
||||
|
|
||||
|
* more accurate error reporting. Currently, udns always returns TEMPFAIL, |
||||
|
but don't specify why it happened (ENOMEM, timeout, etc). |
||||
|
|
||||
|
* check the error value returned by recvfrom() and |
||||
|
sendto() and determine which errors to ignore. |
||||
|
|
||||
|
* maybe merge dns_timeouts() and dns_ioevent(), to have |
||||
|
only one entry point for everything? For traditional |
||||
|
select-loop-based eventloop it may be easier, but for |
||||
|
callback-driven event loops the two should be separate. |
||||
|
Provide an option, or a single dns_events() entry point |
||||
|
for select-loop approach, or just call dns_ioevent() |
||||
|
from within dns_timeouts() (probably after renaming |
||||
|
it to be dns_events()) ? |
||||
|
|
||||
|
* implement /etc/hosts lookup too, ala [c-]ares?? |
||||
|
|
||||
|
* sortlist support? |
||||
|
|
||||
|
* windows port? Oh no please!.. At least, I can't do it myself |
||||
|
because of the lack of platform. |
||||
|
Ok ok, the Windows port is in progress. Christian Prahauser |
||||
|
from cosy.sbg.ac.at is helping with that. |
||||
|
Other folks done some more work in this area. |
@ -0,0 +1,167 @@ |
|||||
|
#! /bin/sh |
||||
|
# $Id: configure,v 1.4 2007/01/07 23:19:40 mjt Exp $ |
||||
|
# autoconf-style configuration script |
||||
|
# |
||||
|
|
||||
|
set -e |
||||
|
|
||||
|
name=udns |
||||
|
|
||||
|
if [ -f udns.h -a -f udns_resolver.c ] ; then : |
||||
|
else |
||||
|
echo "configure: error: sources not found at `pwd`" >&2 |
||||
|
exit 1 |
||||
|
fi |
||||
|
|
||||
|
options="ipv6" |
||||
|
|
||||
|
for opt in $options; do |
||||
|
eval enable_$opt= |
||||
|
done |
||||
|
|
||||
|
if [ -f config.status ]; then |
||||
|
. ./config.status |
||||
|
fi |
||||
|
|
||||
|
enable() { |
||||
|
opt=`echo "$1" | sed 's/^--[^-]*-//'` |
||||
|
case "$opt" in |
||||
|
ipv6|stats|master_dump|zlib|dso) ;; |
||||
|
master-dump) opt=master_dump ;; |
||||
|
*) echo "configure: unrecognized option \`$1'" >&2; exit 1;; |
||||
|
esac |
||||
|
eval enable_$opt=$2 |
||||
|
} |
||||
|
|
||||
|
while [ $# -gt 0 ]; do |
||||
|
case "$1" in |
||||
|
--disable-*|--without-*|--no-*) enable "$1" n;; |
||||
|
--enable-*|--with-*) enable "$1" y;; |
||||
|
--help | --hel | --he | --h | -help | -hel | -he | -h ) |
||||
|
cat <<EOF |
||||
|
configure: configure $name package. |
||||
|
Usage: ./configure [options] |
||||
|
where options are: |
||||
|
--enable-option, --with-option -- |
||||
|
enable the named option/feature |
||||
|
--disable-option, --without-option, --no-option -- |
||||
|
disable the named option/feature |
||||
|
--help - print this help and exit |
||||
|
Optional features (all enabled by default if system supports a feature): |
||||
|
ipv6 - enable/disable IP version 6 (IPv6) support |
||||
|
EOF |
||||
|
exit 0 |
||||
|
;; |
||||
|
*) echo "configure: unknown option \`$1'" >&2; exit 1 ;; |
||||
|
esac |
||||
|
shift |
||||
|
done |
||||
|
|
||||
|
. ./configure.lib |
||||
|
|
||||
|
ac_msg "configure" |
||||
|
ac_result "$name package" |
||||
|
|
||||
|
ac_prog_c_compiler_v |
||||
|
ac_prog_ranlib_v |
||||
|
|
||||
|
ac_ign ac_yesno "for getopt()" ac_have GETOPT ac_link <<EOF |
||||
|
#include <stdio.h> |
||||
|
extern int optind; |
||||
|
extern char *optarg; |
||||
|
extern int getopt(int, char **, char *); |
||||
|
int main(int argc, char **argv) { |
||||
|
getopt(argc, argv, "abc"); |
||||
|
return optarg ? optind : 0; |
||||
|
} |
||||
|
EOF |
||||
|
|
||||
|
ac_ign \ |
||||
|
ac_yesno "for inet_pton() && inet_ntop()" \ |
||||
|
ac_have INET_PTON_NTOP \ |
||||
|
ac_link <<EOF |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/socket.h> |
||||
|
#include <arpa/inet.h> |
||||
|
int main() { |
||||
|
char buf[64]; |
||||
|
long x = 0; |
||||
|
inet_pton(AF_INET, &x, buf); |
||||
|
return inet_ntop(AF_INET, &x, buf, sizeof(buf)); |
||||
|
} |
||||
|
EOF |
||||
|
|
||||
|
if ac_yesno "for socklen_t" ac_compile <<EOF |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/socket.h> |
||||
|
int foo() { socklen_t len; len = 0; return len; } |
||||
|
EOF |
||||
|
then : |
||||
|
else |
||||
|
ac_define socklen_t int |
||||
|
fi |
||||
|
|
||||
|
if ac_library_find_v 'socket and connect' "" "-lsocket -lnsl" <<EOF |
||||
|
int main() { socket(); connect(); return 0; } |
||||
|
EOF |
||||
|
then : |
||||
|
else |
||||
|
ac_fatal "cannot find libraries needed for sockets" |
||||
|
fi |
||||
|
|
||||
|
if [ n != "$enable_ipv6" ]; then |
||||
|
if ac_yesno "for IPv6" ac_have IPv6 ac_compile <<EOF |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/socket.h> |
||||
|
#include <netinet/in.h> |
||||
|
int main() { |
||||
|
struct sockaddr_in6 sa; |
||||
|
sa.sin6_family = AF_INET6; |
||||
|
return 0; |
||||
|
} |
||||
|
EOF |
||||
|
then : |
||||
|
elif [ "$enable_ipv6" ]; then |
||||
|
ac_fatal "IPv6 is requested but not available" |
||||
|
fi |
||||
|
fi # !disable_ipv6? |
||||
|
|
||||
|
if ac_yesno "for poll()" ac_have POLL ac_link <<EOF |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/poll.h> |
||||
|
int main() { |
||||
|
struct pollfd pfd[2]; |
||||
|
return poll(pfd, 2, 10); |
||||
|
} |
||||
|
EOF |
||||
|
then : |
||||
|
else |
||||
|
ac_ign ac_yesno "for sys/select.h" ac_have SYS_SELECT_H ac_cpp <<EOF |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/select.h> |
||||
|
EOF |
||||
|
fi |
||||
|
|
||||
|
ac_config_h |
||||
|
ac_output Makefile |
||||
|
ac_msg "creating config.status" |
||||
|
rm -f config.status |
||||
|
{ |
||||
|
echo "# automatically generated by configure to hold command-line options" |
||||
|
echo |
||||
|
found= |
||||
|
for opt in $options; do |
||||
|
eval val=\$enable_$opt |
||||
|
if [ -n "$val" ]; then |
||||
|
echo enable_$opt=$val |
||||
|
found=y |
||||
|
fi |
||||
|
done |
||||
|
if [ ! "$found" ]; then |
||||
|
echo "# (no options encountered)" |
||||
|
fi |
||||
|
} > config.status |
||||
|
ac_result ok |
||||
|
|
||||
|
ac_result "all done." |
||||
|
exit 0 |
@ -0,0 +1,268 @@ |
|||||
|
# configure.lib |
||||
|
# a library of shell routines for simple autoconf system |
||||
|
# |
||||
|
|
||||
|
set -e |
||||
|
ac_substitutes= |
||||
|
rm -f conftest* config.log |
||||
|
exec 5>config.log |
||||
|
cat <<EOF >&5 |
||||
|
This file contains any messages produced by compilers etc while |
||||
|
running configure, to aid debugging if configure script makes a mistake. |
||||
|
|
||||
|
EOF |
||||
|
|
||||
|
case `echo "a\c"` in |
||||
|
*c*) ac_en=-n ac_ec= ;; |
||||
|
*) ac_en= ac_ec='\c' ;; |
||||
|
esac |
||||
|
|
||||
|
##### Messages |
||||
|
ac_msg() { |
||||
|
echo $ac_en "$*... $ac_ec" |
||||
|
echo ">>> $*" >&5 |
||||
|
} |
||||
|
ac_checking() { |
||||
|
echo $ac_en "checking $*... $ac_ec" |
||||
|
echo ">>> checking $*" >&5 |
||||
|
} |
||||
|
ac_result() { |
||||
|
echo "$1" |
||||
|
echo "=== $1" >&5 |
||||
|
} |
||||
|
ac_fatal() { |
||||
|
echo "configure: fatal: $*" >&2 |
||||
|
echo "=== FATAL: $*" >&5 |
||||
|
exit 1 |
||||
|
} |
||||
|
ac_warning() { |
||||
|
echo "configure: warning: $*" >&2 |
||||
|
echo "=== WARNING: $*" >&5 |
||||
|
} |
||||
|
ac_ign() { |
||||
|
"$@" || : |
||||
|
} |
||||
|
|
||||
|
# ac_run command... |
||||
|
# captures output in conftest.out |
||||
|
ac_run() { |
||||
|
# apparently UnixWare (for one) /bin/sh optimizes the following "if" |
||||
|
# "away", by checking if there's such a command BEFORE redirecting |
||||
|
# output. So error message (like "gcc: command not found") goes |
||||
|
# to stderr instead of to conftest.out, and `cat conftest.out' below |
||||
|
# fails. |
||||
|
if "$@" >conftest.out 2>&1; then |
||||
|
return 0 |
||||
|
else |
||||
|
echo "==== Command invocation failed. Command line was:" >&5 |
||||
|
echo "$*" >&5 |
||||
|
echo "==== compiler input was:" >&5 |
||||
|
cat conftest.c >&5 |
||||
|
echo "==== output was:" >&5 |
||||
|
cat conftest.out >&5 |
||||
|
echo "====" >&5 |
||||
|
return 1 |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
# common case for ac_verbose: yes/no result |
||||
|
ac_yesno() { |
||||
|
ac_checking "$1" |
||||
|
shift |
||||
|
if "$@"; then |
||||
|
ac_result yes |
||||
|
return 0 |
||||
|
else |
||||
|
ac_result no |
||||
|
return 1 |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
ac_subst() { |
||||
|
ac_substitutes="$ac_substitutes $*" |
||||
|
} |
||||
|
|
||||
|
ac_define() { |
||||
|
CDEFS="$CDEFS -D$1=${2:-1}" |
||||
|
} |
||||
|
|
||||
|
ac_have() { |
||||
|
ac_what=$1; shift |
||||
|
if "$@"; then |
||||
|
ac_define HAVE_$ac_what |
||||
|
eval ac_have_$ac_what=yes |
||||
|
return 0 |
||||
|
else |
||||
|
eval ac_have_$ac_what=no |
||||
|
return 1 |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
##### Compiling, linking |
||||
|
|
||||
|
# run a compiler |
||||
|
ac_run_compiler() { |
||||
|
rm -f conftest*; cat >conftest.c |
||||
|
ac_run $CC $CFLAGS $CDEFS "$@" conftest.c |
||||
|
} |
||||
|
|
||||
|
ac_compile() { |
||||
|
ac_run_compiler -c |
||||
|
} |
||||
|
|
||||
|
ac_link() { |
||||
|
ac_run_compiler -o conftest $LIBS "$@" |
||||
|
} |
||||
|
|
||||
|
ac_cpp() { |
||||
|
ac_run_compiler -E "$@" |
||||
|
} |
||||
|
|
||||
|
### check for C compiler. Set $CC, $CFLAGS etc |
||||
|
ac_prog_c_compiler_v() { |
||||
|
ac_checking "for C compiler" |
||||
|
rm -f conftest* |
||||
|
echo 'int main(int argc, char **argv) { return 0; }' >conftest.c |
||||
|
|
||||
|
if [ -n "$CC" ]; then |
||||
|
if ac_run $CC -o conftest conftest.c && ac_run ./conftest; then |
||||
|
ac_result "\$CC ($CC)" |
||||
|
else |
||||
|
ac_result no |
||||
|
ac_fatal "\$CC ($CC) is not a working compiler" |
||||
|
fi |
||||
|
else |
||||
|
for cc in gcc cc ; do |
||||
|
if ac_run $cc -o conftest conftest.c && ac_run ./conftest; then |
||||
|
ac_result "$cc" |
||||
|
CC=$cc |
||||
|
break |
||||
|
fi |
||||
|
done |
||||
|
if [ -z "$CC" ]; then |
||||
|
ac_result no |
||||
|
ac_fatal "no working C compiler found in \$PATH. please set \$CC variable" |
||||
|
fi |
||||
|
fi |
||||
|
if [ -z "$CFLAGS" ]; then |
||||
|
if ac_yesno "whenever C compiler ($CC) is GNU CC" \ |
||||
|
ac_grep_cpp yEs_mAsTeR <<EOF |
||||
|
#ifdef __GNUC__ |
||||
|
yEs_mAsTeR; |
||||
|
#endif |
||||
|
EOF |
||||
|
then |
||||
|
CFLAGS="-Wall -W -O2 -pipe" |
||||
|
else |
||||
|
CFLAGS=-O |
||||
|
fi |
||||
|
fi |
||||
|
cc="$CC $CFLAGS" |
||||
|
ccld="$cc" |
||||
|
if [ -n "$LDFLAGS" ]; then ccld="$ccld $LDFLAGS"; fi |
||||
|
if [ -n "$LIBS" ]; then ccld="$ccld $LIBS"; fi |
||||
|
if ac_yesno "whenever the C compiler ($ccld) |
||||
|
can produce executables" \ |
||||
|
ac_compile_run <<EOF |
||||
|
int main() { return 0; } |
||||
|
EOF |
||||
|
then : |
||||
|
else |
||||
|
ac_fatal "no working C compiler found" |
||||
|
fi |
||||
|
LD='$(CC)' |
||||
|
[ -n "$AR" ] || AR=ar |
||||
|
[ -n "$ARFLAGS" ] || ARFLAGS=rv |
||||
|
[ -n "$AWK" ] || AWK=awk |
||||
|
ac_substitutes="$ac_substitutes CC CFLAGS CDEFS LD LDFLAGS LIBS AR ARFLAGS AWK" |
||||
|
} |
||||
|
|
||||
|
|
||||
|
ac_prog_ranlib_v() { |
||||
|
ac_checking "for ranlib" |
||||
|
if [ -n "$RANLIB" ]; then |
||||
|
ac_result "\$RANLIB ($RANLIB)" |
||||
|
else |
||||
|
ifs="$IFS" |
||||
|
IFS=: |
||||
|
for dir in $PATH; do |
||||
|
[ -n "$dir" ] || dir=. |
||||
|
if [ -f $dir/ranlib ]; then |
||||
|
RANLIB=ranlib |
||||
|
break |
||||
|
fi |
||||
|
done |
||||
|
IFS="$ifs" |
||||
|
if [ -z "$RANLIB" ]; then ac_result no; RANLIB=: |
||||
|
else ac_result "$RANLIB" |
||||
|
fi |
||||
|
fi |
||||
|
ac_substitutes="$ac_substitutes RANLIB" |
||||
|
} |
||||
|
|
||||
|
ac_library_find_v() { |
||||
|
ac_checking "for libraries needed for $1" |
||||
|
shift |
||||
|
fond= |
||||
|
rm -f conftest*; cat >conftest.c |
||||
|
for lib in "$@"; do |
||||
|
if ac_run $CC $CFLAGS $LDFLAGS conftest.c -o conftest $LIBS $lib; then |
||||
|
found=y |
||||
|
break |
||||
|
fi |
||||
|
done |
||||
|
if [ ! "$found" ]; then |
||||
|
ac_result "not found" |
||||
|
return 1 |
||||
|
fi |
||||
|
if [ -z "$lib" ]; then |
||||
|
ac_result "ok (none needed)" |
||||
|
else |
||||
|
ac_result "ok ($lib)" |
||||
|
LIBS="$LIBS $lib" |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
ac_compile_run() { |
||||
|
ac_link "$@" && ac_run ./conftest |
||||
|
} |
||||
|
|
||||
|
ac_grep_cpp() { |
||||
|
pattern="$1"; shift |
||||
|
ac_cpp "$@" && grep "$pattern" conftest.out >/dev/null |
||||
|
} |
||||
|
|
||||
|
ac_output() { |
||||
|
for var in $ac_substitutes; do |
||||
|
eval echo "\"s|@$var@|\$$var|\"" |
||||
|
done >conftest.sed |
||||
|
for file in "$@"; do |
||||
|
ac_msg "creating $file" |
||||
|
if [ -f $file.in ]; then |
||||
|
sed -f conftest.sed $file.in > $file.tmp |
||||
|
mv -f $file.tmp $file |
||||
|
ac_result ok |
||||
|
else |
||||
|
ac_result failed |
||||
|
ac_fatal "$file.in not found" |
||||
|
fi |
||||
|
done |
||||
|
rm -f conftest* |
||||
|
} |
||||
|
|
||||
|
ac_config_h() { |
||||
|
h=${1:-config.h} |
||||
|
ac_msg "creating $h" |
||||
|
rm -f $1.tmp |
||||
|
echo "/* automatically generated by configure. */" > $h.tmp |
||||
|
echo "$CDEFS" | tr ' ' ' |
||||
|
' | sed -e 's/^-D/#define /' -e 's/=/ /' >> $h.tmp |
||||
|
if [ -f $h ] && cmp -s $h.tmp $h ; then |
||||
|
rm -f $h.tmp |
||||
|
ac_result unchanged |
||||
|
else |
||||
|
mv -f $h.tmp $h |
||||
|
ac_result ok |
||||
|
fi |
||||
|
CDEFS=-DHAVE_CONFIG_H |
||||
|
} |
@ -0,0 +1,136 @@ |
|||||
|
udns (0.0.9) unstable; urgency=low |
||||
|
|
||||
|
* s/EOVERFLOW/ENFILE, partly to make win32 happy |
||||
|
|
||||
|
* several win32 fixes |
||||
|
|
||||
|
* don't use `class' in udns.h, to make C++ happy |
||||
|
(thanks Markus Koetter for pointing this out) |
||||
|
|
||||
|
* fixed CNAME handling in dnsget tool. Another Thank You! goes |
||||
|
to Markus Koetter. |
||||
|
|
||||
|
* NAPTR (RFC3403) support, thanks to Mikael Magnusson |
||||
|
<mikma at users.sourceforge.net> for this. |
||||
|
|
||||
|
* more Win32 fixes from Mikael Magnusson. I have to admit |
||||
|
I never tried to compile it on Win32. |
||||
|
|
||||
|
* added NOTES file |
||||
|
|
||||
|
* reworked initialisation stuff. Minor API changes -- new dns_reset(), |
||||
|
dns_init() now has one more argument, corrections to dns_close(), |
||||
|
dns_open(), dns_free(). Cleaned up *_internal() routines. |
||||
|
|
||||
|
* moved dns_init() routine into separate file. |
||||
|
|
||||
|
* reworked dn suffix searching. As a result, query only has |
||||
|
dnsq_dn[] field -- no header and EDNS0 "suffix", and query |
||||
|
packet is now formatted in dns_send() |
||||
|
|
||||
|
* added inet_XtoX.c - public domain implementations of inet_pton() |
||||
|
and inet_ntop(), inet_aton() and inet_ntoa() routines. |
||||
|
|
||||
|
* added getopt.c - public domain implementation of getopt() routine. |
||||
|
|
||||
|
* switched to autoconf-style configuration |
||||
|
|
||||
|
* introduce dns_random16() to generate query IDs |
||||
|
(currently based on gettimeofday.tv_usec) |
||||
|
|
||||
|
* dnsget: fix printing of -t ANY and -c any records, |
||||
|
thanks to Jaroslaw Rafa |
||||
|
|
||||
|
* implement dns_ntop() and dns_pton() as either wrappers or |
||||
|
reimplementations (using inet_XtoX.c) of inet_ntop() and inet_pton(). |
||||
|
Too much troubles with portability - it was a complete mess, each |
||||
|
OS has its own problems with them. |
||||
|
And use those routines everywhere. |
||||
|
|
||||
|
* s/WIN32/WINDOWS/g to allow building on WIN64. Oh well. |
||||
|
|
||||
|
* try to find query by ID first, don't drop header-only replies early. |
||||
|
This is in order to support FORMERR replies from nameservers which |
||||
|
don't understand EDNS0. |
||||
|
|
||||
|
* retry queries w/o EDNS0 if sent with it and if |
||||
|
server reported FORMERR or NOTIMPL |
||||
|
|
||||
|
* fixed debian/copyright and debian/control |
||||
|
|
||||
|
* rblcheck revamp |
||||
|
|
||||
|
-- Michael Tokarev <mjt@corpit.ru> Tue, 16 Jan 2007 00:00:28 +0300 |
||||
|
|
||||
|
udns (0.0.8) unstable; urgency=low |
||||
|
|
||||
|
* don't compare sockaddr_in's, but individual parts only |
||||
|
(on some OSes, there are additional fields in this structure |
||||
|
so memcmp() does not quite work) |
||||
|
|
||||
|
* use dnsc_t instead of unsigned char for DNs everywhere |
||||
|
|
||||
|
* SRV records (rfc2782) parsing, thanks to |
||||
|
Thadeu Lima de Souza Cascardo. |
||||
|
|
||||
|
* manpage fixes |
||||
|
|
||||
|
-- Michael Tokarev <mjt@corpit.ru> Mon, 12 Sep 2005 16:06:45 +0400 |
||||
|
|
||||
|
udns (0.0.7) unstable; urgency=low |
||||
|
|
||||
|
* added dnsget.1 and rblcheck.1 manpages. |
||||
|
|
||||
|
* internal: use generic list implementation in udns_resolver.c |
||||
|
|
||||
|
* don't assume only backward DN pointers in replies, allow forward |
||||
|
pointers too. This is quite large change, involves changing |
||||
|
parsing API all over the places. |
||||
|
|
||||
|
* internal: typedef dnsc_t and dnscc_t for [const] unsigned char, to |
||||
|
make function prototypes shorter to better fit on a single line. |
||||
|
|
||||
|
* in parsing routines, verify (assert) that the query type |
||||
|
is the one we can handle. |
||||
|
|
||||
|
* recognize names (and resolve them) as nameservers in dnsget. |
||||
|
|
||||
|
* when new request is submitted, don't send it immediately, but |
||||
|
add it into the head of the active queue with deadline=0. |
||||
|
This will allow us to tweak some query settings before it will |
||||
|
be processed. |
||||
|
Note API change: removed `now' argument from all dns_submit_*() |
||||
|
routines. |
||||
|
|
||||
|
* use single per-context user timer, not per-query. |
||||
|
Note API change: different user timer callback |
||||
|
|
||||
|
* add dnsc_salen field -- length of the socket address used |
||||
|
|
||||
|
* fix dns_set_opt(DNS_OPT_FLAGS) which didn't work before |
||||
|
|
||||
|
* allow to set some options for a context wich is open but with no |
||||
|
active queries |
||||
|
|
||||
|
-- Michael Tokarev <mjt@corpit.ru> Thu, 5 May 2005 23:14:29 +0400 |
||||
|
|
||||
|
udns (0.0.6) unstable; urgency=low |
||||
|
|
||||
|
* 0.0.6 release. |
||||
|
ALOT of changes all over. Keep 'em in CVS logs! |
||||
|
|
||||
|
-- Michael Tokarev <mjt@corpit.ru> Fri, 8 Apr 2005 19:51:38 +0400 |
||||
|
|
||||
|
udns (0.0.5) unstable; urgency=low |
||||
|
|
||||
|
* Initial Release. |
||||
|
* Provides 3 packages: |
||||
|
libudns0 - shared library |
||||
|
libudns-dev - development files and static library |
||||
|
udns-utils - dnsget, rblcheck |
||||
|
|
||||
|
-- Michael Tokarev <mjt@corpit.ru> Thu, 7 Apr 2005 00:05:24 +0400 |
||||
|
|
||||
|
Local variables: |
||||
|
mode: debian-changelog |
||||
|
End: |
@ -0,0 +1,33 @@ |
|||||
|
Source: udns |
||||
|
Priority: optional |
||||
|
Maintainer: Michael Tokarev <mjt@corpit.ru> |
||||
|
Build-Depends: debhelper (>= 4.0.0) |
||||
|
Standards-Version: 3.7.2 |
||||
|
|
||||
|
Package: libudns0 |
||||
|
Section: libs |
||||
|
Architecture: any |
||||
|
Depends: ${shlibs:Depends} |
||||
|
Description: async-capable DNS stub resolver library |
||||
|
libudns0 package provides libudns shared library needed |
||||
|
to run programs using it |
||||
|
|
||||
|
Package: libudns-dev |
||||
|
Section: libdevel |
||||
|
Architecture: any |
||||
|
Depends: libudns0 (= ${Source-Version}) |
||||
|
Description: async-capable DNS stub resolver library, development files |
||||
|
This package provides development files needed |
||||
|
to build programs using udns library |
||||
|
|
||||
|
Package: udns-utils |
||||
|
Section: net |
||||
|
Architecture: any |
||||
|
Depends: ${shlibs:Depends} |
||||
|
Conflicts: rblcheck |
||||
|
Description: Several DNS-related utilities built on top of udns library |
||||
|
This package includes the following utilities: |
||||
|
dnsget - a simple DNS query tool, like `host' or `dig' for usage from |
||||
|
a command line, and dnsip, dnsname etc for usage in scripts |
||||
|
rblcheck - DNSBL (rbl) checker |
||||
|
All the utilities are built using udns library |
@ -0,0 +1,23 @@ |
|||||
|
This is udns, written and maintained by Michael Tokarev <mjt@corpit.ru> |
||||
|
|
||||
|
The original source can always be found at: |
||||
|
http://www.corpit.ru/mjt/udns.html |
||||
|
|
||||
|
Copyright (C) 2005,2006,2007 Michael Tokarev |
||||
|
|
||||
|
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.1 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 |
||||
|
General Lesser Public License for more details. |
||||
|
|
||||
|
You should have received a copy of the GNU Lesser General Public |
||||
|
License along with this library; if not, write to the Free Software |
||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
|
|
||||
|
On Debian systems, the complete text of the GNU Lesser General |
||||
|
Public License can be found in `/usr/share/common-licenses/LGPL'. |
@ -0,0 +1,93 @@ |
|||||
|
#!/usr/bin/make -f |
||||
|
# -*- makefile -*- |
||||
|
# This file was originally written by Joey Hess and Craig Small. |
||||
|
# As a special exception, when this file is copied by dh-make into a |
||||
|
# dh-make output file, you may use that output file without restriction. |
||||
|
# This special exception was added by Craig Small in version 0.37 of dh-make. |
||||
|
|
||||
|
# Uncomment this to turn on verbose mode. |
||||
|
#export DH_VERBOSE=1 |
||||
|
export DH_COMPAT=4 |
||||
|
|
||||
|
CFLAGS = -Wall -W -Wmissing-prototypes -g |
||||
|
CDEFS = -DHAVE_POOL |
||||
|
|
||||
|
INSTALL = install |
||||
|
INSTALL_PROGRAM = $(INSTALL) -p |
||||
|
INSTALL_DATA = $(INSTALL) -p -m0644 |
||||
|
|
||||
|
ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) |
||||
|
CFLAGS += -O0 |
||||
|
else |
||||
|
CFLAGS += -O2 |
||||
|
endif |
||||
|
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) |
||||
|
INSTALL_PROGRAM += -s |
||||
|
endif |
||||
|
ifeq (,$(findstring debug,$(DEB_BUILD_OPTIONS))) |
||||
|
# CDEFS += -DNDEBUG |
||||
|
endif |
||||
|
|
||||
|
SOVER = 0 |
||||
|
|
||||
|
config.h: ./configure Makefile.in |
||||
|
dh_testdir |
||||
|
./configure --enable-ipv6 |
||||
|
|
||||
|
build: build-stamp |
||||
|
build-stamp: config.h |
||||
|
dh_testdir |
||||
|
$(MAKE) CFLAGS="$(CFLAGS)" SOVER=$(SOVER) \ |
||||
|
staticlib sharedlib rblcheck_s dnsget_s |
||||
|
mv -f dnsget_s dnsget |
||||
|
mv -f rblcheck_s rblcheck |
||||
|
mv -f libudns_s.so libudns.so |
||||
|
echo |
||||
|
touch $@ |
||||
|
|
||||
|
clean: |
||||
|
dh_testdir |
||||
|
rm -f build-stamp |
||||
|
if [ -f Makefile ]; then $(MAKE) distclean; fi |
||||
|
dh_clean |
||||
|
|
||||
|
install: build |
||||
|
dh_testdir |
||||
|
dh_testroot |
||||
|
dh_clean |
||||
|
dh_installdirs |
||||
|
dh_installdocs -A NEWS |
||||
|
|
||||
|
# libudns |
||||
|
dh_install -plibudns$(SOVER) libudns.so.$(SOVER) usr/lib |
||||
|
|
||||
|
# libudns-dev |
||||
|
dh_install -plibudns-dev libudns.a libudns.so usr/lib |
||||
|
dh_install -plibudns-dev udns.h usr/include |
||||
|
dh_installman -plibudns-dev udns.3 |
||||
|
dh_installdocs -plibudns-dev TODO NOTES |
||||
|
dh_installexamples -plibudns-dev ex-rdns.c |
||||
|
|
||||
|
# udns-utils |
||||
|
dh_install -pudns-utils dnsget rblcheck usr/bin |
||||
|
dh_installman -pudns-utils dnsget.1 rblcheck.1 |
||||
|
|
||||
|
binary-indep: build install |
||||
|
|
||||
|
binary-arch: build install |
||||
|
dh_testdir |
||||
|
dh_testroot |
||||
|
dh_installchangelogs |
||||
|
dh_installdocs |
||||
|
dh_strip |
||||
|
dh_compress |
||||
|
dh_fixperms |
||||
|
dh_makeshlibs -V |
||||
|
dh_installdeb |
||||
|
dh_shlibdeps -L libudns$(SOVER) -l . |
||||
|
dh_gencontrol |
||||
|
dh_md5sums |
||||
|
dh_builddeb |
||||
|
|
||||
|
binary: binary-indep binary-arch |
||||
|
.PHONY: build clean binary-indep binary-arch binary install |
@ -0,0 +1,182 @@ |
|||||
|
.\" $Id: dnsget.1,v 1.3 2005/04/20 00:55:34 mjt Exp $ |
||||
|
.\" dnsget manpage |
||||
|
.\" |
||||
|
.\" Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru> |
||||
|
.\" This file is part of UDNS library, an async DNS stub resolver. |
||||
|
.\" |
||||
|
.\" 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.1 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, in file named COPYING.LGPL; if not, |
||||
|
.\" write to the Free Software Foundation, Inc., 59 Temple Place, |
||||
|
.\" Suite 330, Boston, MA 02111-1307 USA |
||||
|
|
||||
|
.TH dnsget 1 "Apr 2005" "User Utilities" |
||||
|
|
||||
|
.SH NAME |
||||
|
dnsget \- DNS lookup utility |
||||
|
|
||||
|
.SH SYNOPSYS |
||||
|
.B dnsget |
||||
|
.RB [\| \-v \||\| \-q \|] |
||||
|
.RB [\| \-c |
||||
|
.IR class \|] |
||||
|
.RB [\| \-t |
||||
|
.IR type \|] |
||||
|
.RB [\| \-o |
||||
|
.IR option : value \] |
||||
|
.IR name \|.\|.\|. |
||||
|
|
||||
|
.SH DESCRIPTION |
||||
|
.B dnsget |
||||
|
is a simple command-line to perform DNS lookups, similar to |
||||
|
.BR host (1) |
||||
|
and |
||||
|
.BR dig (1). |
||||
|
It is useable for both interactive/debugging scenarious and |
||||
|
in scripts. |
||||
|
The program is implemented using |
||||
|
.BR udns (3) |
||||
|
library. |
||||
|
|
||||
|
.PP |
||||
|
By default, |
||||
|
.B dnsget |
||||
|
produces a human-readable output, similar to |
||||
|
.RS |
||||
|
.nf |
||||
|
alias.example.com. CNAME www.example.com. |
||||
|
www.example.com. A 192.168.1.1 |
||||
|
www.example.com. MX 10 mx.example.com. |
||||
|
.fi |
||||
|
.RE |
||||
|
which is just sufficient to see how a given name resolves. |
||||
|
Output format is controllable with |
||||
|
.B \-v |
||||
|
and |
||||
|
.B \-q |
||||
|
options -- the former increases verbosity level up to printing |
||||
|
the whole DNS contents of all packets sent and received, which |
||||
|
is suitable for debugging DNS problems, while the latter reduces |
||||
|
the level, making output more quiet, up to bare result with no |
||||
|
error messages, which is good for scripts. |
||||
|
|
||||
|
.SH OPTIONS |
||||
|
|
||||
|
The following options are recognized by |
||||
|
.BR dnsget : |
||||
|
|
||||
|
.TP |
||||
|
.B \-v |
||||
|
produce more detailed output. More |
||||
|
.BR \-v 's |
||||
|
means more details will be produced. With single |
||||
|
.BR \-v , dnsget |
||||
|
will print contents of all received DNS packets (in a readable format), |
||||
|
while with |
||||
|
.BR \-vv , |
||||
|
it will output all outgoing DNS packets too. |
||||
|
|
||||
|
.TP |
||||
|
.B \-q |
||||
|
the opposite for \fB\-v\fR -- produce less detailed output. |
||||
|
With single |
||||
|
.BR \-q , dnsget |
||||
|
will only show (decoded) data from final DNS resource records (RR), |
||||
|
while |
||||
|
.B \-qq |
||||
|
also suppresses error messages. |
||||
|
|
||||
|
.TP |
||||
|
\fB\-t \fItype\fR |
||||
|
request record(s) of the given type \fItype\fR. By default, |
||||
|
.B dnsget |
||||
|
will ask for IPv4 address (A) record, or for PTR record if the |
||||
|
argument in question is an IPv4 or IPv6 address. Recognized |
||||
|
types include A, AAAA, MX, TXT, CNAME, PTR, NS, SOA, ANY and |
||||
|
others. |
||||
|
|
||||
|
.TP |
||||
|
\fB\-c \fIclass\fR |
||||
|
request DNS record(s) of the given class \fIclass\fR. By |
||||
|
default |
||||
|
.B dnsget |
||||
|
uses IN class. Valid classes include IN, CH, HS, ANY. |
||||
|
|
||||
|
.TP |
||||
|
.B \-a |
||||
|
(compatibility option). Equivalent to setting query type to |
||||
|
.B ANY |
||||
|
and increasing verbosity level |
||||
|
.RB ( \-v ). |
||||
|
|
||||
|
.TP |
||||
|
.B \-C |
||||
|
(planned) |
||||
|
|
||||
|
.TP |
||||
|
.B \-x |
||||
|
(planned) |
||||
|
|
||||
|
.TP |
||||
|
\fB\-o \fIoption\fR:\fIvalue\fR |
||||
|
Set resolver option \fIoption\fR to the value \fIvalue\fR |
||||
|
(may be specified several times). The same as setting |
||||
|
.RB $ RES_OPTIONS |
||||
|
environment variable. The following options are recognized: |
||||
|
.RS |
||||
|
.TP |
||||
|
\fBtimeout\fR:\fIsec\fR |
||||
|
Set initial query timeout to \fIsec\fR. |
||||
|
.TP |
||||
|
\fBattempts\fR:\fInum\fR |
||||
|
(re)try every query \fInum\fR times before failing. |
||||
|
.TP |
||||
|
\fBudpbuf\fR:\fIbytes\fR |
||||
|
set DNS UDP buffer size to \fIbytes\fR bytes. Valid values |
||||
|
are from 512 to 65535. If \fIbytes\fR is greather than 512, |
||||
|
EDNS0 (RFC 2671) extensions will be used. |
||||
|
.TP |
||||
|
\fBport\fR:\fInum\fR |
||||
|
Use given UDP port number \fInum\fR instead of the default port 53 (domain). |
||||
|
.RE |
||||
|
|
||||
|
.TP |
||||
|
\fB\-n \fInameserver\fR |
||||
|
Use the given nameserver(s) (may be specified more than once) |
||||
|
instead of the default. Using this option has the same same effect as |
||||
|
.RB $ NSCACHEIP |
||||
|
or |
||||
|
.RB $ NAMESERVERS |
||||
|
environment variables, with the only difference that only IPv4 addresses |
||||
|
are recognized for now, and it is possible to specify names (which will |
||||
|
be resolved using default settings) instead of IP addresses. |
||||
|
|
||||
|
.TP |
||||
|
.B \-h |
||||
|
print short help and exit. |
||||
|
|
||||
|
.SH "RETURN VALUE" |
||||
|
When all names where resovled successefully, |
||||
|
.B dnsget |
||||
|
exits with zero exit status. If at least one name was not found, |
||||
|
.B dnsget |
||||
|
will exit with return code 100. If some other error occured during |
||||
|
name resolution, it will exit with code 99. In case of usage or |
||||
|
initialization error, |
||||
|
.B dnsget |
||||
|
will return 1. |
||||
|
|
||||
|
.SH "SEE ALSO" |
||||
|
.BR host (1) |
||||
|
.BR dig (1) |
||||
|
.BR resolv.conf (5) |
||||
|
.BR udns (3). |
@ -0,0 +1,726 @@ |
|||||
|
/* $Id: dnsget.c,v 1.31 2007/01/08 01:14:44 mjt Exp $
|
||||
|
simple host/dig-like application using UDNS library |
||||
|
|
||||
|
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru> |
||||
|
This file is part of UDNS library, an async DNS stub resolver. |
||||
|
|
||||
|
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.1 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, in file named COPYING.LGPL; if not, |
||||
|
write to the Free Software Foundation, Inc., 59 Temple Place, |
||||
|
Suite 330, Boston, MA 02111-1307 USA |
||||
|
|
||||
|
*/ |
||||
|
|
||||
|
#ifdef HAVE_CONFIG_H |
||||
|
# include "config.h" |
||||
|
#endif |
||||
|
#ifdef WINDOWS |
||||
|
#include <windows.h> |
||||
|
#include <winsock2.h> |
||||
|
#else |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/socket.h> |
||||
|
#include <netinet/in.h> |
||||
|
#include <sys/time.h> |
||||
|
#include <unistd.h> |
||||
|
#endif |
||||
|
#include <time.h> |
||||
|
#include <stdarg.h> |
||||
|
#include <errno.h> |
||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <string.h> |
||||
|
#include "udns.h" |
||||
|
|
||||
|
#ifndef HAVE_GETOPT |
||||
|
# include "getopt.c" |
||||
|
#endif |
||||
|
|
||||
|
#ifndef AF_INET6 |
||||
|
# define AF_INET6 10 |
||||
|
#endif |
||||
|
|
||||
|
static char *progname; |
||||
|
static int verbose = 1; |
||||
|
static int errors; |
||||
|
static int notfound; |
||||
|
|
||||
|
/* verbosity level:
|
||||
|
* <0 - bare result |
||||
|
* 0 - bare result and error messages |
||||
|
* 1 - readable result |
||||
|
* 2 - received packet contents and `trying ...' stuff |
||||
|
* 3 - sent and received packet contents |
||||
|
*/ |
||||
|
|
||||
|
static void die(int errnum, const char *fmt, ...) { |
||||
|
va_list ap; |
||||
|
fprintf(stderr, "%s: ", progname); |
||||
|
va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); |
||||
|
if (errnum) fprintf(stderr, ": %s\n", strerror(errnum)); |
||||
|
else putc('\n', stderr); |
||||
|
fflush(stderr); |
||||
|
exit(1); |
||||
|
} |
||||
|
|
||||
|
static const char *dns_xntop(int af, const void *src) { |
||||
|
static char buf[6*5+4*4]; |
||||
|
return dns_ntop(af, src, buf, sizeof(buf)); |
||||
|
} |
||||
|
|
||||
|
struct query { |
||||
|
const char *name; /* original query string */ |
||||
|
unsigned char *dn; /* the DN being looked up */ |
||||
|
enum dns_type qtyp; /* type of the query */ |
||||
|
}; |
||||
|
|
||||
|
static void query_free(struct query *q) { |
||||
|
free(q->dn); |
||||
|
free(q); |
||||
|
} |
||||
|
|
||||
|
static struct query * |
||||
|
query_new(const char *name, const unsigned char *dn, enum dns_type qtyp) { |
||||
|
struct query *q = malloc(sizeof(*q)); |
||||
|
unsigned l = dns_dnlen(dn); |
||||
|
unsigned char *cdn = malloc(l); |
||||
|
if (!q || !cdn) die(0, "out of memory"); |
||||
|
memcpy(cdn, dn, l); |
||||
|
q->name = name; |
||||
|
q->dn = cdn; |
||||
|
q->qtyp = qtyp; |
||||
|
return q; |
||||
|
} |
||||
|
|
||||
|
static enum dns_class qcls = DNS_C_IN; |
||||
|
|
||||
|
static void |
||||
|
dnserror(struct query *q, int errnum) { |
||||
|
if (verbose >= 0) |
||||
|
fprintf(stderr, "%s: unable to lookup %s record for %s: %s\n", progname, |
||||
|
dns_typename(q->qtyp), dns_dntosp(q->dn), dns_strerror(errnum)); |
||||
|
if (errnum == DNS_E_NXDOMAIN || errnum == DNS_E_NODATA) |
||||
|
++notfound; |
||||
|
else |
||||
|
++errors; |
||||
|
query_free(q); |
||||
|
} |
||||
|
|
||||
|
static const unsigned char * |
||||
|
printtxt(const unsigned char *c) { |
||||
|
unsigned n = *c++; |
||||
|
const unsigned char *e = c + n; |
||||
|
if (verbose > 0) while(c < e) { |
||||
|
if (*c < ' ' || *c >= 127) printf("\\%02x", *c); |
||||
|
else if (*c == '\\' || *c == '"') printf("\\%c", *c); |
||||
|
else putchar(*c); |
||||
|
++c; |
||||
|
} |
||||
|
else |
||||
|
fwrite(c, n, 1, stdout); |
||||
|
return e; |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
printhex(const unsigned char *c, const unsigned char *e) { |
||||
|
while(c < e) |
||||
|
printf("%02x", *c++); |
||||
|
} |
||||
|
|
||||
|
static unsigned char to_b64[] = |
||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
||||
|
|
||||
|
static void |
||||
|
printb64(const unsigned char *c, const unsigned char *e) { |
||||
|
while(c < e) { |
||||
|
putchar(to_b64[c[0] >> 2]); |
||||
|
if (c+1 < e) { |
||||
|
putchar(to_b64[(c[0] & 0x3) << 4 | c[1] >> 4]); |
||||
|
if (c+2 < e) { |
||||
|
putchar(to_b64[(c[1] & 0xf) << 2 | c[2] >> 6]); |
||||
|
putchar(to_b64[c[2] & 0x3f]); |
||||
|
} |
||||
|
else { |
||||
|
putchar(to_b64[(c[1] & 0xf) << 2]); |
||||
|
putchar('='); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
else { |
||||
|
putchar(to_b64[(c[0] & 0x3) << 4]); |
||||
|
putchar('='); |
||||
|
putchar('='); |
||||
|
break; |
||||
|
} |
||||
|
c += 3; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
printdate(time_t time) { |
||||
|
struct tm *tm = gmtime(&time); |
||||
|
printf("%04d%02d%02d%02d%02d%02d", |
||||
|
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, |
||||
|
tm->tm_hour, tm->tm_min, tm->tm_sec); |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
printrr(const struct dns_parse *p, struct dns_rr *rr) { |
||||
|
const unsigned char *pkt = p->dnsp_pkt; |
||||
|
const unsigned char *end = p->dnsp_end; |
||||
|
const unsigned char *dptr = rr->dnsrr_dptr; |
||||
|
const unsigned char *dend = rr->dnsrr_dend; |
||||
|
unsigned char *dn = rr->dnsrr_dn; |
||||
|
const unsigned char *c; |
||||
|
unsigned n; |
||||
|
|
||||
|
if (verbose > 0) { |
||||
|
if (verbose > 1) { |
||||
|
if (!p->dnsp_rrl && !rr->dnsrr_dn[0] && rr->dnsrr_typ == DNS_T_OPT) { |
||||
|
printf(";EDNS0 OPT record (UDPsize: %d): %d bytes\n", |
||||
|
rr->dnsrr_cls, rr->dnsrr_dsz); |
||||
|
return; |
||||
|
} |
||||
|
n = printf("%s.", dns_dntosp(rr->dnsrr_dn)); |
||||
|
printf("%s%u\t%s\t%s\t", |
||||
|
n > 15 ? "\t" : n > 7 ? "\t\t" : "\t\t\t", |
||||
|
rr->dnsrr_ttl, |
||||
|
dns_classname(rr->dnsrr_cls), |
||||
|
dns_typename(rr->dnsrr_typ)); |
||||
|
} |
||||
|
else |
||||
|
printf("%s. %s ", dns_dntosp(rr->dnsrr_dn), dns_typename(rr->dnsrr_typ)); |
||||
|
} |
||||
|
|
||||
|
switch(rr->dnsrr_typ) { |
||||
|
|
||||
|
case DNS_T_CNAME: |
||||
|
case DNS_T_PTR: |
||||
|
case DNS_T_NS: |
||||
|
case DNS_T_MB: |
||||
|
case DNS_T_MD: |
||||
|
case DNS_T_MF: |
||||
|
case DNS_T_MG: |
||||
|
case DNS_T_MR: |
||||
|
if (dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN) <= 0) goto xperr; |
||||
|
printf("%s.", dns_dntosp(dn)); |
||||
|
break; |
||||
|
|
||||
|
case DNS_T_A: |
||||
|
if (rr->dnsrr_dsz != 4) goto xperr; |
||||
|
printf("%d.%d.%d.%d", dptr[0], dptr[1], dptr[2], dptr[3]); |
||||
|
break; |
||||
|
|
||||
|
case DNS_T_AAAA: |
||||
|
if (rr->dnsrr_dsz != 16) goto xperr; |
||||
|
printf("%s", dns_xntop(AF_INET6, dptr)); |
||||
|
break; |
||||
|
|
||||
|
case DNS_T_MX: |
||||
|
c = dptr + 2; |
||||
|
if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) goto xperr; |
||||
|
printf("%d %s.", dns_get16(dptr), dns_dntosp(dn)); |
||||
|
break; |
||||
|
|
||||
|
case DNS_T_TXT: |
||||
|
/* first verify it */ |
||||
|
for(c = dptr; c < dend; c += n) { |
||||
|
n = *c++; |
||||
|
if (c + n > dend) goto xperr; |
||||
|
} |
||||
|
c = dptr; n = 0; |
||||
|
while (c < dend) { |
||||
|
if (verbose > 0) printf(n++ ? "\" \"":"\""); |
||||
|
c = printtxt(c); |
||||
|
} |
||||
|
if (verbose > 0) putchar('"'); |
||||
|
break; |
||||
|
|
||||
|
case DNS_T_HINFO: /* CPU, OS */ |
||||
|
c = dptr; |
||||
|
n = *c++; if ((c += n) >= dend) goto xperr; |
||||
|
n = *c++; if ((c += n) != dend) goto xperr; |
||||
|
c = dptr; |
||||
|
if (verbose > 0) putchar('"'); |
||||
|
c = printtxt(c); |
||||
|
if (verbose > 0) printf("\" \""); else putchar(' '); |
||||
|
printtxt(c); |
||||
|
if (verbose > 0) putchar('"'); |
||||
|
break; |
||||
|
|
||||
|
case DNS_T_WKS: |
||||
|
c = dptr; |
||||
|
if (dptr + 4 + 2 >= end) goto xperr; |
||||
|
printf("%s %d", dns_xntop(AF_INET, dptr), dptr[4]); |
||||
|
c = dptr + 5; |
||||
|
for (n = 0; c < dend; ++c, n += 8) { |
||||
|
if (*c) { |
||||
|
unsigned b; |
||||
|
for (b = 0; b < 8; ++b) |
||||
|
if (*c & (1 << (7-b))) printf(" %d", n + b); |
||||
|
} |
||||
|
} |
||||
|
break; |
||||
|
|
||||
|
case DNS_T_SRV: /* prio weight port targetDN */ |
||||
|
c = dptr; |
||||
|
c += 2 + 2 + 2; |
||||
|
if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) goto xperr; |
||||
|
c = dptr; |
||||
|
printf("%d %d %d %s.", |
||||
|
dns_get16(c+0), dns_get16(c+2), dns_get16(c+4), |
||||
|
dns_dntosp(dn)); |
||||
|
break; |
||||
|
|
||||
|
case DNS_T_NAPTR: /* order pref flags serv regexp repl */ |
||||
|
c = dptr; |
||||
|
c += 4; /* order, pref */ |
||||
|
for (n = 0; n < 3; ++n) |
||||
|
if (c >= dend) goto xperr; |
||||
|
else c += *c + 1; |
||||
|
if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) goto xperr; |
||||
|
c = dptr; |
||||
|
printf("%u %u", dns_get16(c+0), dns_get16(c+2)); |
||||
|
c += 4; |
||||
|
for(n = 0; n < 3; ++n) { |
||||
|
putchar(' '); |
||||
|
if (verbose > 0) putchar('"'); |
||||
|
c = printtxt(c); |
||||
|
if (verbose > 0) putchar('"'); |
||||
|
} |
||||
|
printf(" %s.", dns_dntosp(dn)); |
||||
|
break; |
||||
|
|
||||
|
case DNS_T_KEY: /* flags(2) proto(1) algo(1) pubkey */ |
||||
|
c = dptr; |
||||
|
if (c + 2 + 1 + 1 > dend) goto xperr; |
||||
|
printf("%d %d %d", dns_get16(c), c[2], c[3]); |
||||
|
c += 2 + 1 + 1; |
||||
|
if (c < dend) { |
||||
|
putchar(' '); |
||||
|
printb64(c, dend); |
||||
|
} |
||||
|
break; |
||||
|
|
||||
|
case DNS_T_SIG: |
||||
|
/* type(2) algo(1) labels(1) ottl(4) sexp(4) sinc(4) tag(2) sdn sig */ |
||||
|
c = dptr; |
||||
|
c += 2 + 1 + 1 + 4 + 4 + 4 + 2; |
||||
|
if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0) goto xperr; |
||||
|
printf("%d %u %u %u ", |
||||
|
dns_get16(dptr), dptr[2], dptr[3], dns_get32(dptr+4)); |
||||
|
printdate(dns_get32(dptr+8)); |
||||
|
putchar(' '); |
||||
|
printdate(dns_get32(dptr+12)); |
||||
|
printf(" %d %s. ", dns_get16(dptr+10), dns_dntosp(dn)); |
||||
|
printb64(c, dend); |
||||
|
break; |
||||
|
|
||||
|
#if 0 /* unused RR types? */
|
||||
|
case DNS_T_DS: |
||||
|
c = dptr; |
||||
|
if (c + 2 + 2 >= dend) goto xperr; |
||||
|
printf("%u %u %u ", dns_get16(c), c[2], c[3]); |
||||
|
printhex(c + 4, dend); |
||||
|
break; |
||||
|
|
||||
|
case DNS_T_NSEC: |
||||
|
c = dptr; |
||||
|
if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0) goto xperr; |
||||
|
printf("%s.", dns_dntosp(dn)); |
||||
|
unfinished. |
||||
|
break; |
||||
|
#endif |
||||
|
|
||||
|
|
||||
|
case DNS_T_SOA: |
||||
|
c = dptr; |
||||
|
if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || |
||||
|
dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || |
||||
|
c + 4*5 != dend) |
||||
|
goto xperr; |
||||
|
dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN); |
||||
|
printf("%s. ", dns_dntosp(dn)); |
||||
|
dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN); |
||||
|
printf("%s. ", dns_dntosp(dn)); |
||||
|
printf("%u %u %u %u %u", |
||||
|
dns_get32(dptr), dns_get32(dptr+4), dns_get32(dptr+8), |
||||
|
dns_get32(dptr+12), dns_get32(dptr+16)); |
||||
|
break; |
||||
|
|
||||
|
case DNS_T_MINFO: |
||||
|
c = dptr; |
||||
|
if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || |
||||
|
dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || |
||||
|
c != dend) |
||||
|
goto xperr; |
||||
|
dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN); |
||||
|
printf("%s. ", dns_dntosp(dn)); |
||||
|
dns_getdn(pkt, &dptr, end, dn, DNS_MAXDN); |
||||
|
printf("%s.", dns_dntosp(dn)); |
||||
|
break; |
||||
|
|
||||
|
case DNS_T_NULL: |
||||
|
default: |
||||
|
printhex(dptr, dend); |
||||
|
break; |
||||
|
} |
||||
|
putchar('\n'); |
||||
|
return; |
||||
|
|
||||
|
xperr: |
||||
|
printf("<parse error>\n"); |
||||
|
++errors; |
||||
|
} |
||||
|
|
||||
|
static int |
||||
|
printsection(struct dns_parse *p, int nrr, const char *sname) { |
||||
|
struct dns_rr rr; |
||||
|
int r; |
||||
|
if (!nrr) return 0; |
||||
|
if (verbose > 1) printf("\n;; %s section (%d):\n", sname, nrr); |
||||
|
|
||||
|
p->dnsp_rrl = nrr; |
||||
|
while((r = dns_nextrr(p, &rr)) > 0) |
||||
|
printrr(p, &rr); |
||||
|
if (r < 0) printf("<<ERROR>>\n"); |
||||
|
return r; |
||||
|
} |
||||
|
|
||||
|
/* dbgcb will only be called if verbose > 1 */ |
||||
|
static void |
||||
|
dbgcb(int code, const struct sockaddr *sa, unsigned slen, |
||||
|
const unsigned char *pkt, int r, |
||||
|
const struct dns_query *unused_q, void *unused_data) { |
||||
|
struct dns_parse p; |
||||
|
const unsigned char *cur, *end; |
||||
|
int numqd; |
||||
|
|
||||
|
if (code > 0) { |
||||
|
printf(";; trying %s.\n", dns_dntosp(dns_payload(pkt))); |
||||
|
printf(";; sending %d bytes query to ", r); |
||||
|
} |
||||
|
else |
||||
|
printf(";; received %d bytes response from ", r); |
||||
|
if (sa->sa_family == AF_INET && slen >= sizeof(struct sockaddr_in)) |
||||
|
printf("%s port %d\n", |
||||
|
dns_xntop(AF_INET, &((struct sockaddr_in*)sa)->sin_addr), |
||||
|
htons(((struct sockaddr_in*)sa)->sin_port)); |
||||
|
#ifdef HAVE_IPv6 |
||||
|
else if (sa->sa_family == AF_INET6 && slen >= sizeof(struct sockaddr_in6)) |
||||
|
printf("%s port %d\n", |
||||
|
dns_xntop(AF_INET6, &((struct sockaddr_in6*)sa)->sin6_addr), |
||||
|
htons(((struct sockaddr_in6*)sa)->sin6_port)); |
||||
|
#endif |
||||
|
else |
||||
|
printf("<<unknown socket type %d>>\n", sa->sa_family); |
||||
|
if (code > 0 && verbose < 3) { |
||||
|
putchar('\n'); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (code == -2) printf(";; reply from unexpected source\n"); |
||||
|
if (code == -5) printf(";; reply to a query we didn't sent (or old)\n"); |
||||
|
if (r < DNS_HSIZE) { |
||||
|
printf(";; short packet (%d bytes)\n", r); |
||||
|
return; |
||||
|
} |
||||
|
if (dns_opcode(pkt) != 0) |
||||
|
printf(";; unexpected opcode %d\n", dns_opcode(pkt)); |
||||
|
if (dns_tc(pkt) != 0) |
||||
|
printf(";; warning: TC bit set, probably incomplete reply\n"); |
||||
|
|
||||
|
printf(";; ->>HEADER<<- opcode: "); |
||||
|
switch(dns_opcode(pkt)) { |
||||
|
case 0: printf("QUERY"); break; |
||||
|
case 1: printf("IQUERY"); break; |
||||
|
case 2: printf("STATUS"); break; |
||||
|
default: printf("UNKNOWN(%u)", dns_opcode(pkt)); break; |
||||
|
} |
||||
|
printf(", status: %s, id: %d, size: %d\n;; flags:", |
||||
|
dns_rcodename(dns_rcode(pkt)), dns_qid(pkt), r); |
||||
|
if (dns_qr(pkt)) printf(" qr"); |
||||
|
if (dns_rd(pkt)) printf(" rd"); |
||||
|
if (dns_ra(pkt)) printf(" ra"); |
||||
|
if (dns_aa(pkt)) printf(" aa"); |
||||
|
if (dns_tc(pkt)) printf(" tc"); |
||||
|
numqd = dns_numqd(pkt); |
||||
|
printf("; QUERY: %d, ANSWER: %d, AUTHORITY: %d, ADDITIONAL: %d\n", |
||||
|
numqd, dns_numan(pkt), dns_numns(pkt), dns_numar(pkt)); |
||||
|
if (numqd != 1) |
||||
|
printf(";; unexpected number of entries in QUERY section: %d\n", |
||||
|
numqd); |
||||
|
printf("\n;; QUERY SECTION (%d):\n", numqd); |
||||
|
cur = dns_payload(pkt); |
||||
|
end = pkt + r; |
||||
|
while(numqd--) { |
||||
|
if (dns_getdn(pkt, &cur, end, p.dnsp_dnbuf, DNS_MAXDN) <= 0 || |
||||
|
cur + 4 > end) { |
||||
|
printf("; invalid query section\n"); |
||||
|
return; |
||||
|
} |
||||
|
r = printf(";%s.", dns_dntosp(p.dnsp_dnbuf)); |
||||
|
printf("%s%s\t%s\n", |
||||
|
r > 23 ? "\t" : r > 15 ? "\t\t" : r > 7 ? "\t\t\t" : "\t\t\t\t", |
||||
|
dns_classname(dns_get16(cur+2)), dns_typename(dns_get16(cur))); |
||||
|
cur += 4; |
||||
|
} |
||||
|
|
||||
|
p.dnsp_pkt = pkt; |
||||
|
p.dnsp_cur = p.dnsp_ans = cur; |
||||
|
p.dnsp_end = end; |
||||
|
p.dnsp_qdn = NULL; |
||||
|
p.dnsp_qcls = p.dnsp_qtyp = 0; |
||||
|
p.dnsp_ttl = 0xffffffffu; |
||||
|
p.dnsp_nrr = 0; |
||||
|
|
||||
|
r = printsection(&p, dns_numan(pkt), "ANSWER"); |
||||
|
if (r == 0) |
||||
|
r = printsection(&p, dns_numns(pkt), "AUTHORITY"); |
||||
|
if (r == 0) |
||||
|
r = printsection(&p, dns_numar(pkt), "ADDITIONAL"); |
||||
|
putchar('\n'); |
||||
|
} |
||||
|
|
||||
|
static void dnscb(struct dns_ctx *ctx, void *result, void *data) { |
||||
|
int r = dns_status(ctx); |
||||
|
struct query *q = data; |
||||
|
struct dns_parse p; |
||||
|
struct dns_rr rr; |
||||
|
unsigned nrr; |
||||
|
unsigned char dn[DNS_MAXDN]; |
||||
|
const unsigned char *pkt, *cur, *end; |
||||
|
if (!result) { |
||||
|
dnserror(q, r); |
||||
|
return; |
||||
|
} |
||||
|
pkt = result; end = pkt + r; cur = dns_payload(pkt); |
||||
|
dns_getdn(pkt, &cur, end, dn, sizeof(dn)); |
||||
|
dns_initparse(&p, NULL, pkt, cur, end); |
||||
|
p.dnsp_qcls = p.dnsp_qtyp = 0; |
||||
|
nrr = 0; |
||||
|
while((r = dns_nextrr(&p, &rr)) > 0) { |
||||
|
if (!dns_dnequal(dn, rr.dnsrr_dn)) continue; |
||||
|
if ((qcls == DNS_C_ANY || qcls == rr.dnsrr_cls) && |
||||
|
(q->qtyp == DNS_T_ANY || q->qtyp == rr.dnsrr_typ)) |
||||
|
++nrr; |
||||
|
else if (rr.dnsrr_typ == DNS_T_CNAME && !nrr) { |
||||
|
if (dns_getdn(pkt, &rr.dnsrr_dptr, end, |
||||
|
p.dnsp_dnbuf, sizeof(p.dnsp_dnbuf)) <= 0 || |
||||
|
rr.dnsrr_dptr != rr.dnsrr_dend) { |
||||
|
r = DNS_E_PROTOCOL; |
||||
|
break; |
||||
|
} |
||||
|
else { |
||||
|
if (verbose == 1) { |
||||
|
printf("%s.", dns_dntosp(dn)); |
||||
|
printf(" CNAME %s.\n", dns_dntosp(p.dnsp_dnbuf)); |
||||
|
} |
||||
|
dns_dntodn(p.dnsp_dnbuf, dn, sizeof(dn)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
if (!r && !nrr) |
||||
|
r = DNS_E_NODATA; |
||||
|
if (r < 0) { |
||||
|
dnserror(q, r); |
||||
|
free(result); |
||||
|
return; |
||||
|
} |
||||
|
if (verbose < 2) { /* else it is already printed by dbgfn */ |
||||
|
dns_rewind(&p, NULL); |
||||
|
p.dnsp_qtyp = q->qtyp == DNS_T_ANY ? 0 : q->qtyp; |
||||
|
p.dnsp_qcls = qcls == DNS_C_ANY ? 0 : qcls; |
||||
|
while(dns_nextrr(&p, &rr)) |
||||
|
printrr(&p, &rr); |
||||
|
} |
||||
|
free(result); |
||||
|
query_free(q); |
||||
|
} |
||||
|
|
||||
|
int main(int argc, char **argv) { |
||||
|
int i; |
||||
|
int fd; |
||||
|
fd_set fds; |
||||
|
struct timeval tv; |
||||
|
time_t now; |
||||
|
char *ns[DNS_MAXSERV]; |
||||
|
int nns = 0; |
||||
|
struct query *q; |
||||
|
enum dns_type qtyp = 0; |
||||
|
struct dns_ctx *nctx = NULL; |
||||
|
|
||||
|
if (!(progname = strrchr(argv[0], '/'))) progname = argv[0]; |
||||
|
else argv[0] = ++progname; |
||||
|
|
||||
|
if (argc <= 1) |
||||
|
die(0, "try `%s -h' for help", progname); |
||||
|
|
||||
|
if (dns_init(NULL, 0) < 0 || !(nctx = dns_new(NULL))) |
||||
|
die(errno, "unable to initialize dns library"); |
||||
|
/* we keep two dns contexts: one may be needed to resolve
|
||||
|
* nameservers if given as names, using default options. |
||||
|
*/ |
||||
|
|
||||
|
while((i = getopt(argc, argv, "vqt:c:an:o:h")) != EOF) switch(i) { |
||||
|
case 'v': ++verbose; break; |
||||
|
case 'q': --verbose; break; |
||||
|
case 't': |
||||
|
if (optarg[0] == '*' && !optarg[1]) |
||||
|
i = DNS_T_ANY; |
||||
|
else if ((i = dns_findtypename(optarg)) <= 0) |
||||
|
die(0, "unrecognized query type `%s'", optarg); |
||||
|
qtyp = i; |
||||
|
break; |
||||
|
case 'c': |
||||
|
if (optarg[0] == '*' && !optarg[1]) |
||||
|
i = DNS_C_ANY; |
||||
|
else if ((i = dns_findclassname(optarg)) < 0) |
||||
|
die(0, "unrecognized query class `%s'", optarg); |
||||
|
qcls = i; |
||||
|
break; |
||||
|
case 'a': |
||||
|
qtyp = DNS_T_ANY; |
||||
|
++verbose; |
||||
|
break; |
||||
|
case 'n': |
||||
|
if (nns >= DNS_MAXSERV) |
||||
|
die(0, "too many nameservers, %d max", DNS_MAXSERV); |
||||
|
ns[nns++] = optarg; |
||||
|
break; |
||||
|
case 'o': |
||||
|
if (dns_set_opts(NULL, optarg) != 0) |
||||
|
die(0, "invalid option string: `%s'", optarg); |
||||
|
break; |
||||
|
case 'h': |
||||
|
printf( |
||||
|
"%s: simple DNS query tool (using udns version %s)\n" |
||||
|
"Usage: %s [options] domain-name...\n" |
||||
|
"where options are:\n" |
||||
|
" -h - print this help and exit\n" |
||||
|
" -v - be more verbose\n" |
||||
|
" -q - be less verbose\n" |
||||
|
" -t type - set query type (A, AAA, PTR etc)\n" |
||||
|
" -c class - set query class (IN (default), CH, HS, *)\n" |
||||
|
" -a - equivalent to -t ANY -v\n" |
||||
|
" -n ns - use given nameserver(s) instead of default\n" |
||||
|
" (may be specified multiple times)\n" |
||||
|
" -o option:value - set resovler option (the same as setting $RES_OPTIONS):\n" |
||||
|
" timeout:sec - initial query timeout\n" |
||||
|
" attempts:num - number of attempt to resovle a query\n" |
||||
|
" ndots:num - if name has more than num dots, lookup it before search\n" |
||||
|
" port:num - port number for queries instead of default 53\n" |
||||
|
" udpbuf:num - size of UDP buffer (use EDNS0 if >512)\n" |
||||
|
" (may be specified more than once)\n" |
||||
|
, progname, dns_version(), progname); |
||||
|
return 0; |
||||
|
default: |
||||
|
die(0, "try `%s -h' for help", progname); |
||||
|
} |
||||
|
|
||||
|
argc -= optind; argv += optind; |
||||
|
if (!argc) |
||||
|
die(0, "no name(s) to query specified"); |
||||
|
|
||||
|
if (nns) { |
||||
|
/* if nameservers given as names, resolve them.
|
||||
|
* We only allow IPv4 nameservers as names for now. |
||||
|
* Ok, it is easy enouth to try both AAAA and A, |
||||
|
* but the question is what to do by default. |
||||
|
*/ |
||||
|
struct sockaddr_in sin; |
||||
|
int j, r = 0, opened = 0; |
||||
|
memset(&sin, 0, sizeof(sin)); |
||||
|
sin.sin_family = AF_INET; |
||||
|
sin.sin_port = htons(dns_set_opt(NULL, DNS_OPT_PORT, -1)); |
||||
|
dns_add_serv(NULL, NULL); |
||||
|
for(i = 0; i < nns; ++i) { |
||||
|
if (dns_pton(AF_INET, ns[i], &sin.sin_addr) <= 0) { |
||||
|
struct dns_rr_a4 *rr; |
||||
|
if (!opened) { |
||||
|
if (dns_open(nctx) < 0) |
||||
|
die(errno, "unable to initialize dns context"); |
||||
|
opened = 1; |
||||
|
} |
||||
|
rr = dns_resolve_a4(nctx, ns[i], 0); |
||||
|
if (!rr) |
||||
|
die(0, "unable to resolve nameserver %s: %s", |
||||
|
ns[i], dns_strerror(dns_status(nctx))); |
||||
|
for(j = 0; j < rr->dnsa4_nrr; ++j) { |
||||
|
sin.sin_addr = rr->dnsa4_addr[j]; |
||||
|
if ((r = dns_add_serv_s(NULL, (struct sockaddr *)&sin)) < 0) |
||||
|
break; |
||||
|
} |
||||
|
free(rr); |
||||
|
} |
||||
|
else |
||||
|
r = dns_add_serv_s(NULL, (struct sockaddr *)&sin); |
||||
|
if (r < 0) |
||||
|
die(errno, "unable to add nameserver %s", |
||||
|
dns_xntop(AF_INET, &sin.sin_addr)); |
||||
|
} |
||||
|
} |
||||
|
dns_free(nctx); |
||||
|
|
||||
|
fd = dns_open(NULL); |
||||
|
if (fd < 0) |
||||
|
die(errno, "unable to initialize dns context"); |
||||
|
|
||||
|
if (verbose > 1) |
||||
|
dns_set_dbgfn(NULL, dbgcb); |
||||
|
|
||||
|
for (i = 0; i < argc; ++i) { |
||||
|
char *name = argv[i]; |
||||
|
union { |
||||
|
struct in_addr addr; |
||||
|
struct in6_addr addr6; |
||||
|
} a; |
||||
|
unsigned char dn[DNS_MAXDN]; |
||||
|
enum dns_type l_qtyp = 0; |
||||
|
int abs; |
||||
|
if (dns_pton(AF_INET, name, &a.addr) > 0) { |
||||
|
dns_a4todn(&a.addr, 0, dn, sizeof(dn)); |
||||
|
l_qtyp = DNS_T_PTR; |
||||
|
abs = 1; |
||||
|
} |
||||
|
#ifdef HAVE_IPv6 |
||||
|
else if (dns_pton(AF_INET6, name, &a.addr6) > 0) { |
||||
|
dns_a6todn(&a.addr6, 0, dn, sizeof(dn)); |
||||
|
l_qtyp = DNS_T_PTR; |
||||
|
abs = 1; |
||||
|
} |
||||
|
#endif |
||||
|
else if (!dns_ptodn(name, strlen(name), dn, sizeof(dn), &abs)) |
||||
|
die(0, "invalid name `%s'\n", name); |
||||
|
else |
||||
|
l_qtyp = DNS_T_A; |
||||
|
if (qtyp) l_qtyp = qtyp; |
||||
|
q = query_new(name, dn, l_qtyp); |
||||
|
if (abs) abs = DNS_NOSRCH; |
||||
|
if (!dns_submit_dn(NULL, dn, qcls, l_qtyp, abs, 0, dnscb, q)) |
||||
|
dnserror(q, dns_status(NULL)); |
||||
|
} |
||||
|
|
||||
|
FD_ZERO(&fds); |
||||
|
now = 0; |
||||
|
while((i = dns_timeouts(NULL, -1, now)) > 0) { |
||||
|
FD_SET(fd, &fds); |
||||
|
tv.tv_sec = i; |
||||
|
tv.tv_usec = 0; |
||||
|
i = select(fd+1, &fds, 0, 0, &tv); |
||||
|
now = time(NULL); |
||||
|
if (i > 0) dns_ioevent(NULL, now); |
||||
|
} |
||||
|
|
||||
|
return errors ? 1 : notfound ? 100 : 0; |
||||
|
} |
@ -0,0 +1,113 @@ |
|||||
|
/* $Id: ex-rdns.c,v 1.8 2007/01/07 22:46:47 mjt Exp $
|
||||
|
parallel rDNS resolver example - read IP addresses from stdin, |
||||
|
write domain names to stdout |
||||
|
|
||||
|
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru> |
||||
|
This file is part of UDNS library, an async DNS stub resolver. |
||||
|
|
||||
|
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.1 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, in file named COPYING.LGPL; if not, |
||||
|
write to the Free Software Foundation, Inc., 59 Temple Place, |
||||
|
Suite 330, Boston, MA 02111-1307 USA |
||||
|
|
||||
|
*/ |
||||
|
|
||||
|
#include <sys/types.h> |
||||
|
#include <sys/socket.h> |
||||
|
#include <netinet/in.h> |
||||
|
#include <sys/poll.h> |
||||
|
#include <unistd.h> |
||||
|
#include <stdio.h> |
||||
|
#include <time.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <string.h> |
||||
|
#include "udns.h" |
||||
|
|
||||
|
static int curq; |
||||
|
|
||||
|
static const char *n2ip(const unsigned char *c) { |
||||
|
static char b[sizeof("255.255.255.255")]; |
||||
|
sprintf(b, "%u.%u.%u.%u", c[0], c[1], c[2], c[3]); |
||||
|
return b; |
||||
|
} |
||||
|
static void dnscb(struct dns_ctx *ctx, struct dns_rr_ptr *rr, void *data) { |
||||
|
const char *ip = n2ip((unsigned char *)&data); |
||||
|
int i; |
||||
|
--curq; |
||||
|
if (rr) { |
||||
|
printf("%s", ip); |
||||
|
for(i = 0; i < rr->dnsptr_nrr; ++i) |
||||
|
printf(" %s", rr->dnsptr_ptr[i]); |
||||
|
putchar('\n'); |
||||
|
free(rr); |
||||
|
} |
||||
|
else |
||||
|
fprintf(stderr, "%s: %s\n", ip, dns_strerror(dns_status(ctx))); |
||||
|
} |
||||
|
|
||||
|
int main(int argc, char **argv) { |
||||
|
int c, t; |
||||
|
time_t now; |
||||
|
int maxq = 10; |
||||
|
struct pollfd pfd; |
||||
|
char linebuf[1024]; |
||||
|
char *eol; |
||||
|
int eof; |
||||
|
|
||||
|
if (dns_init(NULL, 1) < 0) { |
||||
|
fprintf(stderr, "unable to initialize dns library\n"); |
||||
|
return 1; |
||||
|
} |
||||
|
while((c = getopt(argc, argv, "m:r")) != EOF) switch(c) { |
||||
|
case 'm': maxq = atoi(optarg); break; |
||||
|
case 'r': |
||||
|
dns_set_opt(0, DNS_OPT_FLAGS, |
||||
|
dns_set_opt(0, DNS_OPT_FLAGS, -1) | DNS_NORD); |
||||
|
break; |
||||
|
default: return 1; |
||||
|
} |
||||
|
if (argc != optind) return 1; |
||||
|
|
||||
|
pfd.fd = dns_sock(0); |
||||
|
pfd.events = POLLIN; |
||||
|
now = time(NULL); |
||||
|
c = optind; |
||||
|
eof = 0; |
||||
|
while(curq || !eof) { |
||||
|
if (!eof && curq < maxq) { |
||||
|
union { struct in_addr a; void *p; } pa; |
||||
|
if (!fgets(linebuf, sizeof(linebuf), stdin)) { |
||||
|
eof = 1; |
||||
|
continue; |
||||
|
} |
||||
|
eol = strchr(linebuf, '\n'); |
||||
|
if (eol) *eol = '\0'; |
||||
|
if (!linebuf[0]) continue; |
||||
|
if (dns_pton(AF_INET, linebuf, &pa.a) <= 0) |
||||
|
fprintf(stderr, "%s: invalid address\n", linebuf); |
||||
|
else if (dns_submit_a4ptr(0, &pa.a, dnscb, pa.p) == 0) |
||||
|
fprintf(stderr, "%s: unable to submit query: %s\n", |
||||
|
linebuf, dns_strerror(dns_status(0))); |
||||
|
else |
||||
|
++curq; |
||||
|
continue; |
||||
|
} |
||||
|
if (curq) { |
||||
|
t = dns_timeouts(0, -1, now); |
||||
|
t = poll(&pfd, 1, c * 1000); |
||||
|
now = time(NULL); |
||||
|
if (t) dns_ioevent(0, now); |
||||
|
} |
||||
|
} |
||||
|
return 0; |
||||
|
} |
@ -0,0 +1,165 @@ |
|||||
|
/* $Id: getopt.c,v 1.2 2007/01/07 23:19:19 mjt Exp $
|
||||
|
* Simple getopt() implementation. |
||||
|
* |
||||
|
* Standard interface: |
||||
|
* extern int getopt(int argc, char *const *argv, const char *opts); |
||||
|
* extern int optind; current index in argv[] |
||||
|
* extern char *optarg; argument for the current option |
||||
|
* extern int optopt; the current option |
||||
|
* extern int opterr; to control error printing |
||||
|
* |
||||
|
* Some minor extensions: |
||||
|
* ignores leading `+' sign in opts[] (unemplemented GNU extension) |
||||
|
* handles optional arguments, in form "x::" in opts[] |
||||
|
* if opts[] starts with `:', will return `:' in case of missing required |
||||
|
* argument, instead of '?'. |
||||
|
* |
||||
|
* Compile with -DGETOPT_NO_OPTERR to never print errors internally. |
||||
|
* Compile with -DGETOPT_NO_STDIO to use write() calls instead of fprintf() for |
||||
|
* error reporting (ignored with -DGETOPT_NO_OPTERR). |
||||
|
* Compile with -DGETOPT_CLASS=static to get static linkage. |
||||
|
* Compile with -DGETOPT_MY to redefine all visible symbols to be prefixed |
||||
|
* with "my_", like my_getopt instead of getopt. |
||||
|
* Compile with -DTEST to get a test executable. |
||||
|
* |
||||
|
* Written by Michael Tokarev. Public domain. |
||||
|
*/ |
||||
|
|
||||
|
#include <string.h> |
||||
|
|
||||
|
#ifndef GETOPT_CLASS |
||||
|
# define GETOPT_CLASS |
||||
|
#endif |
||||
|
#ifdef GETOPT_MY |
||||
|
# define optarg my_optarg |
||||
|
# define optind my_optind |
||||
|
# define opterr my_opterr |
||||
|
# define optopt my_optopt |
||||
|
# define getopt my_getopt |
||||
|
#endif |
||||
|
|
||||
|
GETOPT_CLASS char *optarg /* = NULL */; |
||||
|
GETOPT_CLASS int optind = 1; |
||||
|
GETOPT_CLASS int opterr = 1; |
||||
|
GETOPT_CLASS int optopt; |
||||
|
|
||||
|
static char *nextc /* = NULL */; |
||||
|
|
||||
|
#if defined(GETOPT_NO_OPTERR) |
||||
|
|
||||
|
#define printerr(argv, msg) |
||||
|
|
||||
|
#elif defined(GETOPT_NO_STDIO) |
||||
|
|
||||
|
extern int write(int, void *, int); |
||||
|
|
||||
|
static void printerr(char *const *argv, const char *msg) { |
||||
|
if (opterr) { |
||||
|
char buf[64]; |
||||
|
unsigned pl = strlen(argv[0]); |
||||
|
unsigned ml = strlen(msg); |
||||
|
char *p; |
||||
|
if (pl + /*": "*/2 + ml + /*" -- c\n"*/6 > sizeof(buf)) { |
||||
|
write(2, argv[0], pl); |
||||
|
p = buf; |
||||
|
} |
||||
|
else { |
||||
|
memcpy(buf, argv[0], ml); |
||||
|
p = buf + pl; |
||||
|
} |
||||
|
*p++ = ':'; *p++ = ' '; |
||||
|
memcpy(p, msg, ml); p += ml; |
||||
|
*p++ = ' '; *p++ = '-'; *p++ = '-'; *p++ = ' '; |
||||
|
*p++ = optopt; |
||||
|
*p++ = '\n'; |
||||
|
write(2, buf, p - buf); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#else |
||||
|
|
||||
|
#include <stdio.h> |
||||
|
static void printerr(char *const *argv, const char *msg) { |
||||
|
if (opterr) |
||||
|
fprintf(stderr, "%s: %s -- %c\n", argv[0], msg, optopt); |
||||
|
} |
||||
|
|
||||
|
#endif |
||||
|
|
||||
|
GETOPT_CLASS int getopt(int argc, char *const *argv, const char *opts) { |
||||
|
char *p; |
||||
|
|
||||
|
optarg = 0; |
||||
|
if (*opts == '+') /* GNU extension (permutation) - isn't supported */ |
||||
|
++opts; |
||||
|
|
||||
|
if (!optind) { /* a way to reset things */ |
||||
|
nextc = 0; |
||||
|
optind = 1; |
||||
|
} |
||||
|
|
||||
|
if (!nextc || !*nextc) { /* advance to the next argv element */ |
||||
|
/* done scanning? */ |
||||
|
if (optind >= argc) |
||||
|
return -1; |
||||
|
/* not an optional argument */ |
||||
|
if (argv[optind][0] != '-') |
||||
|
return -1; |
||||
|
/* bare `-' */ |
||||
|
if (argv[optind][1] == '\0') |
||||
|
return -1; |
||||
|
/* special case `--' argument */ |
||||
|
if (argv[optind][1] == '-' && argv[optind][2] == '\0') { |
||||
|
++optind; |
||||
|
return -1; |
||||
|
} |
||||
|
nextc = argv[optind] + 1; |
||||
|
} |
||||
|
|
||||
|
optopt = *nextc++; |
||||
|
if (!*nextc) |
||||
|
++optind; |
||||
|
p = strchr(opts, optopt); |
||||
|
if (!p || optopt == ':') { |
||||
|
printerr(argv, "illegal option"); |
||||
|
return '?'; |
||||
|
} |
||||
|
if (p[1] == ':') { |
||||
|
if (*nextc) { |
||||
|
optarg = nextc; |
||||
|
nextc = NULL; |
||||
|
++optind; |
||||
|
} |
||||
|
else if (p[2] != ':') { /* required argument */ |
||||
|
if (optind >= argc) { |
||||
|
printerr(argv, "option requires an argument"); |
||||
|
return *opts == ':' ? ':' : '?'; |
||||
|
} |
||||
|
else |
||||
|
optarg = argv[optind++]; |
||||
|
} |
||||
|
} |
||||
|
return optopt; |
||||
|
} |
||||
|
|
||||
|
#ifdef TEST |
||||
|
|
||||
|
#include <stdio.h> |
||||
|
|
||||
|
int main(int argc, char **argv) { |
||||
|
int c; |
||||
|
while((c = getopt(argc, argv, "ab:c::")) != -1) switch(c) { |
||||
|
case 'a': |
||||
|
case 'b': |
||||
|
case 'c': |
||||
|
printf("option %c %s\n", c, optarg ? optarg : "(none)"); |
||||
|
break; |
||||
|
default: |
||||
|
return -1; |
||||
|
} |
||||
|
for(c = optind; c < argc; ++c) |
||||
|
printf("non-opt: %s\n", argv[c]); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
#endif |
@ -0,0 +1,327 @@ |
|||||
|
/* $Id: inet_XtoX.c,v 1.1 2006/12/04 01:55:39 mjt Exp $
|
||||
|
* Simple implementation of the following functions: |
||||
|
* inet_ntop(), inet_ntoa(), inet_pton(), inet_aton(). |
||||
|
* |
||||
|
* Differences from traditional implementaitons: |
||||
|
* o modifies destination buffers even on error return. |
||||
|
* o no fancy (hex, or 1.2) input support in inet_aton() |
||||
|
* o inet_aton() does not accept junk after an IP address. |
||||
|
* o inet_ntop(AF_INET) requires at least 16 bytes in dest, |
||||
|
* and inet_ntop(AF_INET6) at least 40 bytes |
||||
|
* (traditional inet_ntop() will try to fit anyway) |
||||
|
* |
||||
|
* Compile with -Dinet_XtoX_prefix=pfx_ to have pfx_*() instead of inet_*() |
||||
|
* Compile with -Dinet_XtoX_no_ntop or -Dinet_XtoX_no_pton |
||||
|
* to disable net2str or str2net conversions. |
||||
|
* |
||||
|
* #define inet_XtoX_prototypes and #include "this_file.c" |
||||
|
* to get function prototypes only (but not for inet_ntoa()). |
||||
|
* #define inet_XtoX_decl to be `static' for static visibility, |
||||
|
* or use __declspec(dllexport) or somesuch... |
||||
|
* |
||||
|
* Compile with -DTEST to test against stock implementation. |
||||
|
* |
||||
|
* Written by Michael Tokarev. Public domain. |
||||
|
*/ |
||||
|
|
||||
|
#ifdef inet_XtoX_prototypes |
||||
|
|
||||
|
struct in_addr; |
||||
|
|
||||
|
#else |
||||
|
|
||||
|
#include <errno.h> |
||||
|
|
||||
|
#ifdef TEST |
||||
|
|
||||
|
# include <netinet/in.h> |
||||
|
# include <sys/socket.h> |
||||
|
# include <arpa/inet.h> |
||||
|
# include <stdio.h> |
||||
|
# include <stdlib.h> |
||||
|
# include <unistd.h> |
||||
|
# include <string.h> |
||||
|
# undef inet_XtoX_prefix |
||||
|
# define inet_XtoX_prefix mjt_inet_ |
||||
|
# undef inet_XtoX_no_ntop |
||||
|
# undef inet_XtoX_no_pton |
||||
|
|
||||
|
#else /* !TEST */ |
||||
|
|
||||
|
struct in_addr { /* declare it here to avoid messing with headers */ |
||||
|
unsigned char x[4]; |
||||
|
}; |
||||
|
|
||||
|
#endif /* TEST */ |
||||
|
|
||||
|
#endif /* inet_XtoX_prototypes */ |
||||
|
|
||||
|
#ifndef inet_XtoX_prefix |
||||
|
# define inet_XtoX_prefix inet_ |
||||
|
#endif |
||||
|
#ifndef inet_XtoX_decl |
||||
|
# define inet_XtoX_decl /*empty*/ |
||||
|
#endif |
||||
|
|
||||
|
#define cc2_(x,y) cc2__(x,y) |
||||
|
#define cc2__(x,y) x##y |
||||
|
#define fn(x) cc2_(inet_XtoX_prefix,x) |
||||
|
|
||||
|
#ifndef inet_XtoX_no_ntop |
||||
|
|
||||
|
inet_XtoX_decl const char * |
||||
|
fn(ntop)(int af, const void *src, char *dst, unsigned size); |
||||
|
|
||||
|
#ifndef inet_XtoX_prototypes |
||||
|
|
||||
|
static int mjt_ntop4(const void *_src, char *dst, int size) { |
||||
|
unsigned i, x, r; |
||||
|
char *p; |
||||
|
const unsigned char *s = _src; |
||||
|
if (size < 4*4) /* for simplicity, disallow non-max-size buffer */ |
||||
|
return 0; |
||||
|
for (i = 0, p = dst; i < 4; ++i) { |
||||
|
if (i) *p++ = '.'; |
||||
|
x = r = s[i]; |
||||
|
if (x > 99) { *p++ = (char)(r / 100 + '0'); r %= 100; } |
||||
|
if (x > 9) { *p++ = (char)(r / 10 + '0'); r %= 10; } |
||||
|
*p++ = (char)(r + '0'); |
||||
|
} |
||||
|
*p = '\0'; |
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
static char *hexc(char *p, unsigned x) { |
||||
|
static char hex[16] = "0123456789abcdef"; |
||||
|
if (x > 0x0fff) *p++ = hex[(x >>12) & 15]; |
||||
|
if (x > 0x00ff) *p++ = hex[(x >> 8) & 15]; |
||||
|
if (x > 0x000f) *p++ = hex[(x >> 4) & 15]; |
||||
|
*p++ = hex[x & 15]; |
||||
|
return p; |
||||
|
} |
||||
|
|
||||
|
static int mjt_ntop6(const void *_src, char *dst, int size) { |
||||
|
unsigned i; |
||||
|
unsigned short w[8]; |
||||
|
unsigned bs = 0, cs = 0; |
||||
|
unsigned bl = 0, cl = 0; |
||||
|
char *p; |
||||
|
const unsigned char *s = _src; |
||||
|
|
||||
|
if (size < 40) /* for simplicity, disallow non-max-size buffer */ |
||||
|
return 0; |
||||
|
|
||||
|
for(i = 0; i < 8; ++i, s += 2) { |
||||
|
w[i] = (((unsigned short)(s[0])) << 8) | s[1]; |
||||
|
if (!w[i]) { |
||||
|
if (!cl++) cs = i; |
||||
|
} |
||||
|
else { |
||||
|
if (cl > bl) bl = cl, bs = cs; |
||||
|
} |
||||
|
} |
||||
|
if (cl > bl) bl = cl, bs = cs; |
||||
|
p = dst; |
||||
|
if (bl == 1) |
||||
|
bl = 0; |
||||
|
if (bl) { |
||||
|
for(i = 0; i < bs; ++i) { |
||||
|
if (i) *p++ = ':'; |
||||
|
p = hexc(p, w[i]); |
||||
|
} |
||||
|
*p++ = ':'; |
||||
|
i += bl; |
||||
|
if (i == 8) |
||||
|
*p++ = ':'; |
||||
|
} |
||||
|
else |
||||
|
i = 0; |
||||
|
for(; i < 8; ++i) { |
||||
|
if (i) *p++ = ':'; |
||||
|
if (i == 6 && !bs && (bl == 6 || (bl == 5 && w[5] == 0xffff))) |
||||
|
return mjt_ntop4(s - 4, p, size - (p - dst)); |
||||
|
p = hexc(p, w[i]); |
||||
|
} |
||||
|
*p = '\0'; |
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
inet_XtoX_decl const char * |
||||
|
fn(ntop)(int af, const void *src, char *dst, unsigned size) { |
||||
|
switch(af) { |
||||
|
/* don't use AF_*: don't mess with headers */ |
||||
|
case 2: /* AF_INET */ if (mjt_ntop4(src, dst, size)) return dst; break; |
||||
|
case 10: /* AF_INET6 */ if (mjt_ntop6(src, dst, size)) return dst; break; |
||||
|
default: errno = EAFNOSUPPORT; return (char*)0; |
||||
|
} |
||||
|
errno = ENOSPC; |
||||
|
return (char*)0; |
||||
|
} |
||||
|
|
||||
|
inet_XtoX_decl const char * |
||||
|
fn(ntoa)(struct in_addr addr) { |
||||
|
static char buf[4*4]; |
||||
|
mjt_ntop4(&addr, buf, sizeof(buf)); |
||||
|
return buf; |
||||
|
} |
||||
|
|
||||
|
#endif /* inet_XtoX_prototypes */ |
||||
|
#endif /* inet_XtoX_no_ntop */ |
||||
|
|
||||
|
#ifndef inet_XtoX_no_pton |
||||
|
|
||||
|
inet_XtoX_decl int fn(pton)(int af, const char *src, void *dst); |
||||
|
inet_XtoX_decl int fn(aton)(const char *src, struct in_addr *addr); |
||||
|
|
||||
|
#ifndef inet_XtoX_prototypes |
||||
|
|
||||
|
static int mjt_pton4(const char *c, void *dst) { |
||||
|
unsigned char *a = dst; |
||||
|
unsigned n, o; |
||||
|
for (n = 0; n < 4; ++n) { |
||||
|
if (*c < '0' || *c > '9') |
||||
|
return 0; |
||||
|
o = *c++ - '0'; |
||||
|
while(*c >= '0' && *c <= '9') |
||||
|
if ((o = o * 10 + (*c++ - '0')) > 255) |
||||
|
return 0; |
||||
|
if (*c++ != (n == 3 ? '\0' : '.')) |
||||
|
return 0; |
||||
|
*a++ = (unsigned char)o; |
||||
|
} |
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
static int mjt_pton6(const char *c, void *dst) { |
||||
|
unsigned short w[8], *a = w, *z, *i; |
||||
|
unsigned v, o; |
||||
|
const char *sc; |
||||
|
unsigned char *d = dst; |
||||
|
if (*c != ':') z = (unsigned short*)0; |
||||
|
else if (*++c != ':') return 0; |
||||
|
else ++c, z = a; |
||||
|
i = 0; |
||||
|
for(;;) { |
||||
|
v = 0; |
||||
|
sc = c; |
||||
|
for(;;) { |
||||
|
if (*c >= '0' && *c <= '9') o = *c - '0'; |
||||
|
else if (*c >= 'a' && *c <= 'f') o = *c - 'a' + 10; |
||||
|
else if (*c >= 'A' && *c <= 'F') o = *c - 'A' + 10; |
||||
|
else break; |
||||
|
v = (v << 4) | o; |
||||
|
if (v > 0xffff) return 0; |
||||
|
++c; |
||||
|
} |
||||
|
if (sc == c) { |
||||
|
if (z == a && !*c) |
||||
|
break; |
||||
|
else |
||||
|
return 0; |
||||
|
} |
||||
|
if (*c == ':') { |
||||
|
if (a >= w + 8) |
||||
|
return 0; |
||||
|
*a++ = v; |
||||
|
if (*++c == ':') { |
||||
|
if (z) |
||||
|
return 0; |
||||
|
z = a; |
||||
|
if (!*++c) |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
else if (!*c) { |
||||
|
if (a >= w + 8) |
||||
|
return 0; |
||||
|
*a++ = v; |
||||
|
break; |
||||
|
} |
||||
|
else if (*c == '.') { |
||||
|
if (a > w + 6) |
||||
|
return 0; |
||||
|
if (!mjt_pton4(sc, d)) |
||||
|
return 0; |
||||
|
*a++ = ((unsigned)(d[0]) << 8) | d[1]; |
||||
|
*a++ = ((unsigned)(d[2]) << 8) | d[3]; |
||||
|
break; |
||||
|
} |
||||
|
else |
||||
|
return 0; |
||||
|
} |
||||
|
v = w + 8 - a; |
||||
|
if ((v && !z) || (!v && z)) |
||||
|
return 0; |
||||
|
for(i = w; ; ++i) { |
||||
|
if (i == z) |
||||
|
while(v--) { *d++ = '\0'; *d++ = '\0'; } |
||||
|
if (i >= a) |
||||
|
break; |
||||
|
*d++ = (unsigned char)((*i >> 8) & 255); |
||||
|
*d++ = (unsigned char)(*i & 255); |
||||
|
} |
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
inet_XtoX_decl int fn(pton)(int af, const char *src, void *dst) { |
||||
|
switch(af) { |
||||
|
/* don't use AF_*: don't mess with headers */ |
||||
|
case 2 /* AF_INET */: return mjt_pton4(src, dst); |
||||
|
case 10 /* AF_INET6 */: return mjt_pton6(src, dst); |
||||
|
default: errno = EAFNOSUPPORT; return -1; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
inet_XtoX_decl int fn(aton)(const char *src, struct in_addr *addr) { |
||||
|
return mjt_pton4(src, addr); |
||||
|
} |
||||
|
|
||||
|
#endif /* inet_XtoX_prototypes */ |
||||
|
|
||||
|
#endif /* inet_XtoX_no_pton */ |
||||
|
|
||||
|
#ifdef TEST |
||||
|
|
||||
|
int main(int argc, char **argv) { |
||||
|
int i; |
||||
|
char n0[16], n1[16]; |
||||
|
char p0[64], p1[64]; |
||||
|
int af = AF_INET; |
||||
|
int pl = sizeof(p0); |
||||
|
int r0, r1; |
||||
|
const char *s0, *s1; |
||||
|
|
||||
|
while((i = getopt(argc, argv, "46a:p:")) != EOF) switch(i) { |
||||
|
case '4': af = AF_INET; break; |
||||
|
case '6': af = AF_INET6; break; |
||||
|
case 'a': case 'p': pl = atoi(optarg); break; |
||||
|
default: return 1; |
||||
|
} |
||||
|
for(i = optind; i < argc; ++i) { |
||||
|
char *a = argv[i]; |
||||
|
|
||||
|
printf("%s:\n", a); |
||||
|
r0 = inet_pton(af, a, n0); |
||||
|
printf(" p2n stock: %s\n", |
||||
|
(r0 < 0 ? "(notsupp)" : !r0 ? "(inval)" : fn(ntop)(af,n0,p0,sizeof(p0)))); |
||||
|
r1 = fn(pton)(af, a, n1); |
||||
|
printf(" p2n this : %s\n", |
||||
|
(r1 < 0 ? "(notsupp)" : !r1 ? "(inval)" : fn(ntop)(af,n1,p1,sizeof(p1)))); |
||||
|
|
||||
|
if ((r0 > 0) != (r1 > 0) || |
||||
|
(r0 > 0 && r1 > 0 && memcmp(n0, n1, af == AF_INET ? 4 : 16) != 0)) |
||||
|
printf(" DIFFER!\n"); |
||||
|
|
||||
|
s0 = inet_ntop(af, n1, p0, pl); |
||||
|
printf(" n2p stock: %s\n", s0 ? s0 : "(inval)"); |
||||
|
s1 = fn(ntop)(af, n1, p1, pl); |
||||
|
printf(" n2p this : %s\n", s1 ? s1 : "(inval)"); |
||||
|
if ((s0 != 0) != (s1 != 0) || |
||||
|
(s0 && s1 && strcmp(s0, s1) != 0)) |
||||
|
printf(" DIFFER!\n"); |
||||
|
|
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
#endif /* TEST */ |
@ -0,0 +1,151 @@ |
|||||
|
.\" $Id: rblcheck.1,v 1.1 2005/04/24 23:14:23 mjt Exp $ |
||||
|
.\" rblckeck manpage |
||||
|
.\" |
||||
|
.\" Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru> |
||||
|
.\" This file is part of UDNS library, an async DNS stub resolver. |
||||
|
.\" |
||||
|
.\" 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.1 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, in file named COPYING.LGPL; if not, |
||||
|
.\" write to the Free Software Foundation, Inc., 59 Temple Place, |
||||
|
.\" Suite 330, Boston, MA 02111-1307 USA |
||||
|
|
||||
|
.TH rblckeck 1 "Apr 2005" "User Utilities" |
||||
|
|
||||
|
.SH NAME |
||||
|
rblckeck \- DNSBL lookup utility |
||||
|
|
||||
|
.SH SYNOPSYS |
||||
|
.B rblcheck |
||||
|
.RB [\| \-s |
||||
|
.IR zone \|] |
||||
|
.RB [\| \-S |
||||
|
.IR zone\-file \|] |
||||
|
.RB [\| \-c \|] |
||||
|
.RB [\| \-tmvq \|] |
||||
|
.RB [\| \-n |
||||
|
.IR nsaddr \|] |
||||
|
.IR address \|.\|.\|. |
||||
|
|
||||
|
.SH DESCRIPTION |
||||
|
.B rblcheck |
||||
|
is a simple command-line to perform DNSBL (DNS-based blocklists) lookups. |
||||
|
For every IP address (or a name, in which case it will be resolved to an |
||||
|
address first), the utility verifies whenever it is listed in a (list of) |
||||
|
DNS blocklists specified with |
||||
|
.B \-s |
||||
|
or |
||||
|
.B \-S |
||||
|
options, optionally obtains text assotiated with the listing (usually it |
||||
|
is either some description about the reason of the listing or an URL |
||||
|
referring to such a description), and displays results on standard output. |
||||
|
.PP |
||||
|
The program is implemented on top of |
||||
|
.BR udns (3) |
||||
|
library. |
||||
|
|
||||
|
.SH OPTIONS |
||||
|
|
||||
|
The following options are recognized by |
||||
|
.BR rblcheck : |
||||
|
|
||||
|
.TP |
||||
|
.B \-s \fIzone\fR |
||||
|
add the given \fIzone\fR DNSBL name to the list of active zones. |
||||
|
.TP |
||||
|
.B \-S \fIzone-file\fR |
||||
|
add list of zones from the named \fIzone-file\fR to the list of |
||||
|
active zones (the file specifies one zone as the first word on a |
||||
|
line, empty lines and lines starting with `#' character are ignored). |
||||
|
.TP |
||||
|
.B \-c |
||||
|
reset active zone list. |
||||
|
.TP |
||||
|
.B \-v |
||||
|
be more verbose, produce more detailed output. |
||||
|
.TP |
||||
|
.B \-q |
||||
|
the opposite for \fB\-v\fR -- produce less detailed output. |
||||
|
.TP |
||||
|
.B \-t |
||||
|
obtain text for listed addresses. |
||||
|
.TP |
||||
|
.B \-n \fInsaddr\fR |
||||
|
Use the given nameserver (given as IPv4 or IPv6 address) instead of the |
||||
|
default. The same effect may be achieved by setting $NSCACHEIP environment |
||||
|
variable. |
||||
|
.TP |
||||
|
.B \-m |
||||
|
stop after first hit, ie after the first address which is found to be |
||||
|
listed. |
||||
|
|
||||
|
.TP |
||||
|
.B \-h |
||||
|
print short help and exit. |
||||
|
|
||||
|
.PP |
||||
|
If no |
||||
|
.BR \-s , |
||||
|
.BR \-S |
||||
|
and |
||||
|
.B \-c |
||||
|
options are given, |
||||
|
.B rblcheck |
||||
|
will try to obtain list of zones using $RBLCHECK_ZONES environment variable, |
||||
|
or ~/.rblcheckrc, or /etc/rblckechrc files, in that order. If no zones are |
||||
|
found, it will exit unsuccessefully. |
||||
|
|
||||
|
.SH "RETURN VALUE" |
||||
|
When no addresses given are listed and no errors occured, |
||||
|
.B rblcheck |
||||
|
exits with code 0. If at least one address is listed, |
||||
|
.B rblcheck |
||||
|
returns 100. In case of DNS errors, |
||||
|
.B rblcheck |
||||
|
returns 2. |
||||
|
|
||||
|
.SH ENVIRONMENT |
||||
|
|
||||
|
.TP |
||||
|
.B $RBLCHECK_ZONES |
||||
|
if no |
||||
|
.BR \-s , |
||||
|
.B \-S |
||||
|
or |
||||
|
.B \-c |
||||
|
option is given, |
||||
|
.B rblcheck |
||||
|
tries this variable to obtain list of DNSBL zones to check against. |
||||
|
|
||||
|
.SH FILES |
||||
|
|
||||
|
.TP |
||||
|
$HOME/.rblcheckrc and /etc/rblcheckrc |
||||
|
if no |
||||
|
.BR \-s , |
||||
|
.B \-S |
||||
|
or |
||||
|
.B \-c |
||||
|
option is given, and no $RBLCHECK_ZONES environment variable is set, |
||||
|
.B rblcheck |
||||
|
will try the two files (the first one that exists) to obtain list of |
||||
|
DNSBL zones to check against. |
||||
|
Each line specifies one zone (only first word in each line is used). |
||||
|
Empty lines and lines starting with `#' character are ignored. |
||||
|
|
||||
|
.SH "SEE ALSO" |
||||
|
.BR dnsget (1) |
||||
|
.BR resolv.conf (5) |
||||
|
.BR udns (3). |
||||
|
|
||||
|
.SH AUTHOR |
||||
|
This program and manual pages are written by Michael Tokarev. |
@ -0,0 +1,377 @@ |
|||||
|
/* $Id: rblcheck.c,v 1.14 2007/01/10 02:52:51 mjt Exp $
|
||||
|
dnsbl (rbl) checker application |
||||
|
|
||||
|
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru> |
||||
|
This file is part of UDNS library, an async DNS stub resolver. |
||||
|
|
||||
|
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.1 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, in file named COPYING.LGPL; if not, |
||||
|
write to the Free Software Foundation, Inc., 59 Temple Place, |
||||
|
Suite 330, Boston, MA 02111-1307 USA |
||||
|
|
||||
|
*/ |
||||
|
|
||||
|
#ifdef HAVE_CONFIG_H |
||||
|
# include "config.h" |
||||
|
#endif |
||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <string.h> |
||||
|
#ifdef WINDOWS |
||||
|
# include <winsock2.h> |
||||
|
#else |
||||
|
# include <unistd.h> |
||||
|
# include <sys/types.h> |
||||
|
# include <sys/socket.h> |
||||
|
# include <netinet/in.h> |
||||
|
#endif |
||||
|
#include <time.h> |
||||
|
#include <errno.h> |
||||
|
#include <stdarg.h> |
||||
|
#include "udns.h" |
||||
|
|
||||
|
#ifndef HAVE_GETOPT |
||||
|
# include "getopt.c" |
||||
|
#endif |
||||
|
|
||||
|
static const char *version = "udns-rblcheck 0.2"; |
||||
|
static char *progname; |
||||
|
|
||||
|
static void error(int die, const char *fmt, ...) { |
||||
|
va_list ap; |
||||
|
fprintf(stderr, "%s: ", progname); |
||||
|
va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); |
||||
|
putc('\n', stderr); |
||||
|
fflush(stderr); |
||||
|
if (die) |
||||
|
exit(1); |
||||
|
} |
||||
|
|
||||
|
struct rblookup { |
||||
|
struct ipcheck *parent; |
||||
|
struct in_addr key; |
||||
|
const char *zone; |
||||
|
struct dns_rr_a4 *addr; |
||||
|
struct dns_rr_txt *txt; |
||||
|
}; |
||||
|
|
||||
|
struct ipcheck { |
||||
|
const char *name; |
||||
|
int naddr; |
||||
|
int listed; |
||||
|
struct rblookup *lookup; |
||||
|
}; |
||||
|
|
||||
|
#define notlisted ((void*)1) |
||||
|
|
||||
|
static int nzones, nzalloc; |
||||
|
static const char **zones; |
||||
|
|
||||
|
static int do_txt; |
||||
|
static int stopfirst; |
||||
|
static int verbose = 1; |
||||
|
/* verbosity level:
|
||||
|
* <0 - only bare As/TXTs |
||||
|
* 0 - what RBL result |
||||
|
* 1(default) - what is listed by RBL: result |
||||
|
* 2 - what is[not ]listed by RBL: result, name lookups |
||||
|
*/ |
||||
|
|
||||
|
static int listed; |
||||
|
static int failures; |
||||
|
|
||||
|
static void *ecalloc(int size, int cnt) { |
||||
|
void *t = calloc(size, cnt); |
||||
|
if (!t) |
||||
|
error(1, "out of memory"); |
||||
|
return t; |
||||
|
} |
||||
|
|
||||
|
static void addzone(const char *zone) { |
||||
|
if (nzones >= nzalloc) { |
||||
|
const char **zs = (const char**)ecalloc(sizeof(char*), (nzalloc += 16)); |
||||
|
if (zones) { |
||||
|
memcpy(zs, zones, nzones * sizeof(char*)); |
||||
|
free(zones); |
||||
|
} |
||||
|
zones = zs; |
||||
|
} |
||||
|
zones[nzones++] = zone; |
||||
|
} |
||||
|
|
||||
|
static int addzonefile(const char *fname) { |
||||
|
FILE *f = fopen(fname, "r"); |
||||
|
char linebuf[2048]; |
||||
|
if (!f) |
||||
|
return 0; |
||||
|
while(fgets(linebuf, sizeof(linebuf), f)) { |
||||
|
char *p = linebuf, *e; |
||||
|
while(*p == ' ' || *p == '\t') ++p; |
||||
|
if (*p == '#' || *p == '\n') continue; |
||||
|
e = p; |
||||
|
while(*e && *e != ' ' && *e != '\t' && *e != '\n') |
||||
|
++e; |
||||
|
*e = '\0'; |
||||
|
addzone(p); |
||||
|
} |
||||
|
fclose(f); |
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
static void dnserror(struct rblookup *ipl, const char *what) { |
||||
|
char buf[4*4]; |
||||
|
error(0, "unable to %s for %s (%s): %s", |
||||
|
what, dns_ntop(AF_INET, &ipl->key, buf, sizeof(buf)), |
||||
|
ipl->zone, dns_strerror(dns_status(0))); |
||||
|
++failures; |
||||
|
} |
||||
|
|
||||
|
static void display_result(struct ipcheck *ipc) { |
||||
|
int j; |
||||
|
struct rblookup *l, *le; |
||||
|
char buf[4*4]; |
||||
|
if (!ipc->naddr) return; |
||||
|
for (l = ipc->lookup, le = l + nzones * ipc->naddr; l < le; ++l) { |
||||
|
if (!l->addr) continue; |
||||
|
if (verbose < 2 && l->addr == notlisted) continue; |
||||
|
if (verbose >= 0) { |
||||
|
dns_ntop(AF_INET, &l->key, buf, sizeof(buf)); |
||||
|
if (ipc->name) printf("%s[%s]", ipc->name, buf); |
||||
|
else printf("%s", buf); |
||||
|
} |
||||
|
if (l->addr == notlisted) { |
||||
|
printf(" is NOT listed by %s\n", l->zone); |
||||
|
continue; |
||||
|
} |
||||
|
else if (verbose >= 1) |
||||
|
printf(" is listed by %s: ", l->zone); |
||||
|
else if (verbose >= 0) |
||||
|
printf(" %s ", l->zone); |
||||
|
if (verbose >= 1 || !do_txt) |
||||
|
for (j = 0; j < l->addr->dnsa4_nrr; ++j) |
||||
|
printf("%s%s", j ? " " : "", |
||||
|
dns_ntop(AF_INET, &l->addr->dnsa4_addr[j], buf, sizeof(buf))); |
||||
|
if (!do_txt) ; |
||||
|
else if (l->txt) { |
||||
|
for(j = 0; j < l->txt->dnstxt_nrr; ++j) { |
||||
|
unsigned char *t = l->txt->dnstxt_txt[j].txt; |
||||
|
unsigned char *e = t + l->txt->dnstxt_txt[j].len; |
||||
|
printf("%s\"", verbose > 0 ? "\n\t" : j ? " " : ""); |
||||
|
while(t < e) { |
||||
|
if (*t < ' ' || *t >= 127) printf("\\x%02x", *t); |
||||
|
else if (*t == '\\' || *t == '"') printf("\\%c", *t); |
||||
|
else putchar(*t); |
||||
|
++t; |
||||
|
} |
||||
|
putchar('"'); |
||||
|
} |
||||
|
free(l->txt); |
||||
|
} |
||||
|
else |
||||
|
printf("%s<no text available>", verbose > 0 ? "\n\t" : ""); |
||||
|
free(l->addr); |
||||
|
putchar('\n'); |
||||
|
} |
||||
|
free(ipc->lookup); |
||||
|
} |
||||
|
|
||||
|
static void txtcb(struct dns_ctx *ctx, struct dns_rr_txt *r, void *data) { |
||||
|
struct rblookup *ipl = data; |
||||
|
if (r) { |
||||
|
ipl->txt = r; |
||||
|
++ipl->parent->listed; |
||||
|
} |
||||
|
else if (dns_status(ctx) != DNS_E_NXDOMAIN) |
||||
|
dnserror(ipl, "lookup DNSBL TXT record"); |
||||
|
} |
||||
|
|
||||
|
static void a4cb(struct dns_ctx *ctx, struct dns_rr_a4 *r, void *data) { |
||||
|
struct rblookup *ipl = data; |
||||
|
if (r) { |
||||
|
ipl->addr = r; |
||||
|
++listed; |
||||
|
if (do_txt) { |
||||
|
if (dns_submit_a4dnsbl_txt(0, &ipl->key, ipl->zone, txtcb, ipl)) |
||||
|
return; |
||||
|
dnserror(ipl, "submit DNSBL TXT record"); |
||||
|
} |
||||
|
++ipl->parent->listed; |
||||
|
} |
||||
|
else if (dns_status(ctx) != DNS_E_NXDOMAIN) |
||||
|
dnserror(ipl, "lookup DNSBL A record"); |
||||
|
else |
||||
|
ipl->addr = notlisted; |
||||
|
} |
||||
|
|
||||
|
static int |
||||
|
submit_a_queries(struct ipcheck *ipc, |
||||
|
int naddr, const struct in_addr *addr) { |
||||
|
int z, a; |
||||
|
struct rblookup *rl = ecalloc(sizeof(*rl), nzones * naddr); |
||||
|
ipc->lookup = rl; |
||||
|
ipc->naddr = naddr; |
||||
|
for(a = 0; a < naddr; ++a) { |
||||
|
for(z = 0; z < nzones; ++z) { |
||||
|
rl->key = addr[a]; |
||||
|
rl->zone = zones[z]; |
||||
|
rl->parent = ipc; |
||||
|
if (!dns_submit_a4dnsbl(0, &rl->key, rl->zone, a4cb, rl)) |
||||
|
dnserror(rl, "submit DNSBL A query"); |
||||
|
++rl; |
||||
|
} |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
static void namecb(struct dns_ctx *ctx, struct dns_rr_a4 *rr, void *data) { |
||||
|
struct ipcheck *ipc = data; |
||||
|
if (rr) { |
||||
|
submit_a_queries(ipc, rr->dnsa4_nrr, rr->dnsa4_addr); |
||||
|
free(rr); |
||||
|
} |
||||
|
else { |
||||
|
error(0, "unable to lookup `%s': %s", |
||||
|
ipc->name, dns_strerror(dns_status(ctx))); |
||||
|
++failures; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static int submit(struct ipcheck *ipc) { |
||||
|
struct in_addr addr; |
||||
|
if (dns_pton(AF_INET, ipc->name, &addr) > 0) { |
||||
|
submit_a_queries(ipc, 1, &addr); |
||||
|
ipc->name = NULL; |
||||
|
} |
||||
|
else if (!dns_submit_a4(0, ipc->name, 0, namecb, ipc)) { |
||||
|
error(0, "unable to submit name query for %s: %s\n", |
||||
|
ipc->name, dns_strerror(dns_status(0))); |
||||
|
++failures; |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
static void waitdns(struct ipcheck *ipc) { |
||||
|
struct timeval tv; |
||||
|
fd_set fds; |
||||
|
int c; |
||||
|
int fd = dns_sock(NULL); |
||||
|
time_t now = 0; |
||||
|
FD_ZERO(&fds); |
||||
|
while((c = dns_timeouts(NULL, -1, now)) > 0) { |
||||
|
FD_SET(fd, &fds); |
||||
|
tv.tv_sec = c; |
||||
|
tv.tv_usec = 0; |
||||
|
c = select(fd+1, &fds, NULL, NULL, &tv); |
||||
|
now = time(NULL); |
||||
|
if (c > 0) |
||||
|
dns_ioevent(NULL, now); |
||||
|
if (stopfirst && ipc->listed) |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
int main(int argc, char **argv) { |
||||
|
int c; |
||||
|
struct ipcheck ipc; |
||||
|
char *nameserver = NULL; |
||||
|
int zgiven = 0; |
||||
|
|
||||
|
if (!(progname = strrchr(argv[0], '/'))) progname = argv[0]; |
||||
|
else argv[0] = ++progname; |
||||
|
|
||||
|
while((c = getopt(argc, argv, "hqtvms:S:cn:")) != EOF) switch(c) { |
||||
|
case 's': ++zgiven; addzone(optarg); break; |
||||
|
case 'S': |
||||
|
++zgiven; |
||||
|
if (addzonefile(optarg)) break; |
||||
|
error(1, "unable to read zonefile `%s'", optarg); |
||||
|
case 'c': ++zgiven; nzones = 0; break; |
||||
|
case 'q': --verbose; break; |
||||
|
case 'v': ++verbose; break; |
||||
|
case 't': do_txt = 1; break; |
||||
|
case 'n': nameserver = optarg; break; |
||||
|
case 'm': ++stopfirst; break; |
||||
|
case 'h': |
||||
|
printf("%s: %s (udns library version %s).\n", |
||||
|
progname, version, dns_version()); |
||||
|
printf("Usage is: %s [options] address..\n", progname); |
||||
|
printf( |
||||
|
"Where options are:\n" |
||||
|
" -h - print this help and exit\n" |
||||
|
" -s service - add the service (DNSBL zone) to the serice list\n" |
||||
|
" -S service-file - add the DNSBL zone(s) read from the given file\n" |
||||
|
" -c - clear service list\n" |
||||
|
" -v - increase verbosity level (more -vs => more verbose)\n" |
||||
|
" -q - decrease verbosity level (opposite of -v)\n" |
||||
|
" -t - obtain and print TXT records if any\n" |
||||
|
" -m - stop checking after first address match in any list\n" |
||||
|
" -n ipaddr - use the given nameserver instead of the default\n" |
||||
|
"(if no -s or -S option is given, use $RBLCHECK_ZONES, ~/.rblcheckrc\n" |
||||
|
"or /etc/rblcheckrc in that order)\n" |
||||
|
); |
||||
|
return 0; |
||||
|
default: |
||||
|
error(1, "use `%s -h' for help", progname); |
||||
|
} |
||||
|
|
||||
|
if (!zgiven) { |
||||
|
char *s = getenv("RBLCHECK_ZONES"); |
||||
|
if (s) { |
||||
|
char *k; |
||||
|
s = strdup(s); |
||||
|
for(k = strtok(s, " \t"); k; k = strtok(NULL, " \t")) |
||||
|
addzone(k); |
||||
|
free(s); |
||||
|
} |
||||
|
else { /* probably worthless on windows? */ |
||||
|
char *path; |
||||
|
char *home = getenv("HOME"); |
||||
|
if (!home) home = "."; |
||||
|
path = malloc(strlen(home) + 1 + sizeof(".rblcheckrc")); |
||||
|
sprintf(path, "%s/.rblcheckrc", home); |
||||
|
if (!addzonefile(path)) |
||||
|
addzonefile("/etc/rblcheckrc"); |
||||
|
free(path); |
||||
|
} |
||||
|
} |
||||
|
if (!nzones) |
||||
|
error(1, "no service (zone) list specified (-s or -S option)"); |
||||
|
|
||||
|
argv += optind; |
||||
|
argc -= optind; |
||||
|
|
||||
|
if (!argc) |
||||
|
return 0; |
||||
|
|
||||
|
if (dns_init(NULL, 0) < 0) |
||||
|
error(1, "unable to initialize DNS library: %s", strerror(errno)); |
||||
|
if (nameserver) { |
||||
|
dns_add_serv(NULL, NULL); |
||||
|
if (dns_add_serv(NULL, nameserver) < 0) |
||||
|
error(1, "wrong IP address for a nameserver: `%s'", nameserver); |
||||
|
} |
||||
|
if (dns_open(NULL) < 0) |
||||
|
error(1, "unable to initialize DNS library: %s", strerror(errno)); |
||||
|
|
||||
|
for (c = 0; c < argc; ++c) { |
||||
|
if (c && (verbose > 1 || (verbose == 1 && do_txt))) putchar('\n'); |
||||
|
memset(&ipc, 0, sizeof(ipc)); |
||||
|
ipc.name = argv[c]; |
||||
|
submit(&ipc); |
||||
|
waitdns(&ipc); |
||||
|
display_result(&ipc); |
||||
|
if (stopfirst > 1 && listed) break; |
||||
|
} |
||||
|
|
||||
|
return listed ? 100 : failures ? 2 : 0; |
||||
|
} |
File diff suppressed because it is too large
@ -0,0 +1,745 @@ |
|||||
|
/* $Id: udns.h,v 1.51 2007/01/15 21:19:08 mjt Exp $
|
||||
|
header file for the UDNS library. |
||||
|
|
||||
|
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru> |
||||
|
This file is part of UDNS library, an async DNS stub resolver. |
||||
|
|
||||
|
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.1 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, in file named COPYING.LGPL; if not, |
||||
|
write to the Free Software Foundation, Inc., 59 Temple Place, |
||||
|
Suite 330, Boston, MA 02111-1307 USA |
||||
|
|
||||
|
*/ |
||||
|
|
||||
|
#ifndef UDNS_VERSION /* include guard */ |
||||
|
|
||||
|
#define UDNS_VERSION "0.0.9" |
||||
|
|
||||
|
#ifdef WINDOWS |
||||
|
# ifdef UDNS_DYNAMIC_LIBRARY |
||||
|
# ifdef DNS_LIBRARY_BUILD |
||||
|
# define UDNS_API __declspec(dllexport) |
||||
|
# define UDNS_DATA_API __declspec(dllexport) |
||||
|
# else |
||||
|
# define UDNS_API __declspec(dllimport) |
||||
|
# define UDNS_DATA_API __declspec(dllimport) |
||||
|
# endif |
||||
|
# endif |
||||
|
#endif |
||||
|
|
||||
|
#ifndef UDNS_API |
||||
|
# define UDNS_API |
||||
|
#endif |
||||
|
#ifndef UDNS_DATA_API |
||||
|
# define UDNS_DATA_API |
||||
|
#endif |
||||
|
|
||||
|
#include <sys/types.h> /* for time_t */ |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
/* forward declarations if sockets stuff isn't #include'd */ |
||||
|
struct in_addr; |
||||
|
struct in6_addr; |
||||
|
struct sockaddr; |
||||
|
|
||||
|
/**************************************************************************/ |
||||
|
/**************** Common definitions **************************************/ |
||||
|
|
||||
|
UDNS_API const char * |
||||
|
dns_version(void); |
||||
|
|
||||
|
struct dns_ctx; |
||||
|
struct dns_query; |
||||
|
|
||||
|
/* shorthand for [const] unsigned char */ |
||||
|
typedef unsigned char dnsc_t; |
||||
|
typedef const unsigned char dnscc_t; |
||||
|
|
||||
|
#define DNS_MAXDN 255 /* max DN length */ |
||||
|
#define DNS_DNPAD 1 /* padding for DN buffers */ |
||||
|
#define DNS_MAXLABEL 63 /* max DN label length */ |
||||
|
#define DNS_MAXNAME 1024 /* max asciiz domain name length */ |
||||
|
#define DNS_HSIZE 12 /* DNS packet header size */ |
||||
|
#define DNS_PORT 53 /* default domain port */ |
||||
|
#define DNS_MAXSERV 6 /* max servers to consult */ |
||||
|
#define DNS_MAXPACKET 512 /* max traditional-DNS UDP packet size */ |
||||
|
#define DNS_EDNS0PACKET 4096 /* EDNS0 packet size to use */ |
||||
|
|
||||
|
enum dns_class { /* DNS RR Classes */ |
||||
|
DNS_C_INVALID = 0, /* invalid class */ |
||||
|
DNS_C_IN = 1, /* Internet */ |
||||
|
DNS_C_CH = 3, /* CHAOS */ |
||||
|
DNS_C_HS = 4, /* HESIOD */ |
||||
|
DNS_C_ANY = 255 /* wildcard */ |
||||
|
}; |
||||
|
|
||||
|
enum dns_type { /* DNS RR Types */ |
||||
|
DNS_T_INVALID = 0, /* Cookie. */ |
||||
|
DNS_T_A = 1, /* Host address. */ |
||||
|
DNS_T_NS = 2, /* Authoritative server. */ |
||||
|
DNS_T_MD = 3, /* Mail destination. */ |
||||
|
DNS_T_MF = 4, /* Mail forwarder. */ |
||||
|
DNS_T_CNAME = 5, /* Canonical name. */ |
||||
|
DNS_T_SOA = 6, /* Start of authority zone. */ |
||||
|
DNS_T_MB = 7, /* Mailbox domain name. */ |
||||
|
DNS_T_MG = 8, /* Mail group member. */ |
||||
|
DNS_T_MR = 9, /* Mail rename name. */ |
||||
|
DNS_T_NULL = 10, /* Null resource record. */ |
||||
|
DNS_T_WKS = 11, /* Well known service. */ |
||||
|
DNS_T_PTR = 12, /* Domain name pointer. */ |
||||
|
DNS_T_HINFO = 13, /* Host information. */ |
||||
|
DNS_T_MINFO = 14, /* Mailbox information. */ |
||||
|
DNS_T_MX = 15, /* Mail routing information. */ |
||||
|
DNS_T_TXT = 16, /* Text strings. */ |
||||
|
DNS_T_RP = 17, /* Responsible person. */ |
||||
|
DNS_T_AFSDB = 18, /* AFS cell database. */ |
||||
|
DNS_T_X25 = 19, /* X_25 calling address. */ |
||||
|
DNS_T_ISDN = 20, /* ISDN calling address. */ |
||||
|
DNS_T_RT = 21, /* Router. */ |
||||
|
DNS_T_NSAP = 22, /* NSAP address. */ |
||||
|
DNS_T_NSAP_PTR = 23, /* Reverse NSAP lookup (deprecated). */ |
||||
|
DNS_T_SIG = 24, /* Security signature. */ |
||||
|
DNS_T_KEY = 25, /* Security key. */ |
||||
|
DNS_T_PX = 26, /* X.400 mail mapping. */ |
||||
|
DNS_T_GPOS = 27, /* Geographical position (withdrawn). */ |
||||
|
DNS_T_AAAA = 28, /* Ip6 Address. */ |
||||
|
DNS_T_LOC = 29, /* Location Information. */ |
||||
|
DNS_T_NXT = 30, /* Next domain (security). */ |
||||
|
DNS_T_EID = 31, /* Endpoint identifier. */ |
||||
|
DNS_T_NIMLOC = 32, /* Nimrod Locator. */ |
||||
|
DNS_T_SRV = 33, /* Server Selection. */ |
||||
|
DNS_T_ATMA = 34, /* ATM Address */ |
||||
|
DNS_T_NAPTR = 35, /* Naming Authority PoinTeR */ |
||||
|
DNS_T_KX = 36, /* Key Exchange */ |
||||
|
DNS_T_CERT = 37, /* Certification record */ |
||||
|
DNS_T_A6 = 38, /* IPv6 address (deprecates AAAA) */ |
||||
|
DNS_T_DNAME = 39, /* Non-terminal DNAME (for IPv6) */ |
||||
|
DNS_T_SINK = 40, /* Kitchen sink (experimentatl) */ |
||||
|
DNS_T_OPT = 41, /* EDNS0 option (meta-RR) */ |
||||
|
DNS_T_DS = 43, /* DNSSEC */ |
||||
|
DNS_T_NSEC = 47, /* DNSSEC */ |
||||
|
DNS_T_TSIG = 250, /* Transaction signature. */ |
||||
|
DNS_T_IXFR = 251, /* Incremental zone transfer. */ |
||||
|
DNS_T_AXFR = 252, /* Transfer zone of authority. */ |
||||
|
DNS_T_MAILB = 253, /* Transfer mailbox records. */ |
||||
|
DNS_T_MAILA = 254, /* Transfer mail agent records. */ |
||||
|
DNS_T_ANY = 255, /* Wildcard match. */ |
||||
|
DNS_T_ZXFR = 256, /* BIND-specific, nonstandard. */ |
||||
|
DNS_T_MAX = 65536 |
||||
|
}; |
||||
|
|
||||
|
/**************************************************************************/ |
||||
|
/**************** Domain Names (DNs) **************************************/ |
||||
|
|
||||
|
/* return length of the DN */ |
||||
|
UDNS_API unsigned |
||||
|
dns_dnlen(dnscc_t *dn); |
||||
|
|
||||
|
/* return #of labels in a DN */ |
||||
|
UDNS_API unsigned |
||||
|
dns_dnlabels(dnscc_t *dn); |
||||
|
|
||||
|
/* lower- and uppercase single DN char */ |
||||
|
#define DNS_DNLC(c) ((c) >= 'A' && (c) <= 'Z' ? (c) - 'A' + 'a' : (c)) |
||||
|
#define DNS_DNUC(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c)) |
||||
|
|
||||
|
/* compare the DNs, return dnlen of equal or 0 if not */ |
||||
|
UDNS_API unsigned |
||||
|
dns_dnequal(dnscc_t *dn1, dnscc_t *dn2); |
||||
|
|
||||
|
/* copy one DN to another, size checking */ |
||||
|
UDNS_API unsigned |
||||
|
dns_dntodn(dnscc_t *sdn, dnsc_t *ddn, unsigned ddnsiz); |
||||
|
|
||||
|
/* convert asciiz string of length namelen (0 to use strlen) to DN */ |
||||
|
UDNS_API int |
||||
|
dns_ptodn(const char *name, unsigned namelen, |
||||
|
dnsc_t *dn, unsigned dnsiz, int *isabs); |
||||
|
|
||||
|
/* simpler form of dns_ptodn() */ |
||||
|
#define dns_sptodn(name,dn,dnsiz) dns_ptodn((name),0,(dn),(dnsiz),0) |
||||
|
|
||||
|
UDNS_DATA_API extern dnscc_t dns_inaddr_arpa_dn[14]; |
||||
|
#define DNS_A4RSIZE 30 |
||||
|
UDNS_API int |
||||
|
dns_a4todn(const struct in_addr *addr, dnscc_t *tdn, |
||||
|
dnsc_t *dn, unsigned dnsiz); |
||||
|
UDNS_API int |
||||
|
dns_a4ptodn(const struct in_addr *addr, const char *tname, |
||||
|
dnsc_t *dn, unsigned dnsiz); |
||||
|
UDNS_API dnsc_t * |
||||
|
dns_a4todn_(const struct in_addr *addr, dnsc_t *dn, dnsc_t *dne); |
||||
|
|
||||
|
UDNS_DATA_API extern dnscc_t dns_ip6_arpa_dn[10]; |
||||
|
#define DNS_A6RSIZE 74 |
||||
|
UDNS_API int |
||||
|
dns_a6todn(const struct in6_addr *addr, dnscc_t *tdn, |
||||
|
dnsc_t *dn, unsigned dnsiz); |
||||
|
UDNS_API int |
||||
|
dns_a6ptodn(const struct in6_addr *addr, const char *tname, |
||||
|
dnsc_t *dn, unsigned dnsiz); |
||||
|
UDNS_API dnsc_t * |
||||
|
dns_a6todn_(const struct in6_addr *addr, dnsc_t *dn, dnsc_t *dne); |
||||
|
|
||||
|
/* convert DN into asciiz string */ |
||||
|
UDNS_API int |
||||
|
dns_dntop(dnscc_t *dn, char *name, unsigned namesiz); |
||||
|
|
||||
|
/* convert DN into asciiz string, using static buffer (NOT thread-safe!) */ |
||||
|
UDNS_API const char * |
||||
|
dns_dntosp(dnscc_t *dn); |
||||
|
|
||||
|
/* return buffer size (incl. null byte) required for asciiz form of a DN */ |
||||
|
UDNS_API unsigned |
||||
|
dns_dntop_size(dnscc_t *dn); |
||||
|
|
||||
|
/* either wrappers or reimplementations for inet_ntop() and inet_pton() */ |
||||
|
UDNS_API const char *dns_ntop(int af, const void *src, char *dst, int size); |
||||
|
UDNS_API int dns_pton(int af, const char *src, void *dst); |
||||
|
|
||||
|
/**************************************************************************/ |
||||
|
/**************** DNS raw packet layout ***********************************/ |
||||
|
|
||||
|
enum dns_rcode { /* reply codes */ |
||||
|
DNS_R_NOERROR = 0, /* ok, no error */ |
||||
|
DNS_R_FORMERR = 1, /* format error */ |
||||
|
DNS_R_SERVFAIL = 2, /* server failed */ |
||||
|
DNS_R_NXDOMAIN = 3, /* domain does not exists */ |
||||
|
DNS_R_NOTIMPL = 4, /* not implemented */ |
||||
|
DNS_R_REFUSED = 5, /* query refused */ |
||||
|
/* these are for BIND_UPDATE */ |
||||
|
DNS_R_YXDOMAIN = 6, /* Name exists */ |
||||
|
DNS_R_YXRRSET = 7, /* RRset exists */ |
||||
|
DNS_R_NXRRSET = 8, /* RRset does not exist */ |
||||
|
DNS_R_NOTAUTH = 9, /* Not authoritative for zone */ |
||||
|
DNS_R_NOTZONE = 10, /* Zone of record different from zone section */ |
||||
|
/*ns_r_max = 11,*/ |
||||
|
/* The following are TSIG extended errors */ |
||||
|
DNS_R_BADSIG = 16, |
||||
|
DNS_R_BADKEY = 17, |
||||
|
DNS_R_BADTIME = 18 |
||||
|
}; |
||||
|
|
||||
|
static __inline unsigned dns_get16(dnscc_t *s) { |
||||
|
return ((unsigned)s[0]<<8) | s[1]; |
||||
|
} |
||||
|
static __inline unsigned dns_get32(dnscc_t *s) { |
||||
|
return ((unsigned)s[0]<<24) | ((unsigned)s[1]<<16) |
||||
|
| ((unsigned)s[2]<<8) | s[3]; |
||||
|
} |
||||
|
static __inline dnsc_t *dns_put16(dnsc_t *d, unsigned n) { |
||||
|
*d++ = (dnsc_t)((n >> 8) & 255); *d++ = (dnsc_t)(n & 255); return d; |
||||
|
} |
||||
|
static __inline dnsc_t *dns_put32(dnsc_t *d, unsigned n) { |
||||
|
*d++ = (dnsc_t)((n >> 24) & 255); *d++ = (dnsc_t)((n >> 16) & 255); |
||||
|
*d++ = (dnsc_t)((n >> 8) & 255); *d++ = (dnsc_t)(n & 255); |
||||
|
return d; |
||||
|
} |
||||
|
|
||||
|
/* return pseudo-random 16bits number */ |
||||
|
UDNS_API unsigned dns_random16(void); |
||||
|
|
||||
|
/* DNS Header layout */ |
||||
|
enum { |
||||
|
/* bytes 0:1 - query ID */ |
||||
|
DNS_H_QID1 = 0, |
||||
|
DNS_H_QID2 = 1, |
||||
|
DNS_H_QID = DNS_H_QID1, |
||||
|
#define dns_qid(pkt) dns_get16((pkt)+DNS_H_QID) |
||||
|
/* byte 2: flags1 */ |
||||
|
DNS_H_F1 = 2, |
||||
|
DNS_HF1_QR = 0x80, /* query response flag */ |
||||
|
#define dns_qr(pkt) ((pkt)[DNS_H_F1]&DNS_HF1_QR) |
||||
|
DNS_HF1_OPCODE = 0x78, /* opcode, 0 = query */ |
||||
|
#define dns_opcode(pkt) (((pkt)[DNS_H_F1]&DNS_HF1_OPCODE)>>3) |
||||
|
DNS_HF1_AA = 0x04, /* auth answer */ |
||||
|
#define dns_aa(pkt) ((pkt)[DNS_H_F1]&DNS_HF1_AA) |
||||
|
DNS_HF1_TC = 0x02, /* truncation flag */ |
||||
|
#define dns_tc(pkt) ((pkt)[DNS_H_F1]&DNS_HF1_TC) |
||||
|
DNS_HF1_RD = 0x01, /* recursion desired (may be set in query) */ |
||||
|
#define dns_rd(pkt) ((pkt)[DNS_H_F1]&DNS_HF1_RD) |
||||
|
/* byte 3: flags2 */ |
||||
|
DNS_H_F2 = 3, |
||||
|
DNS_HF2_RA = 0x80, /* recursion available */ |
||||
|
#define dns_ra(pkt) ((pkt)[DNS_H_F2]&DNS_HF2_RA) |
||||
|
DNS_HF2_Z = 0x70, /* reserved */ |
||||
|
DNS_HF2_RCODE = 0x0f, /* response code, DNS_R_XXX above */ |
||||
|
#define dns_rcode(pkt) ((pkt)[DNS_H_F2]&DNS_HF2_RCODE) |
||||
|
/* bytes 4:5: qdcount, numqueries */ |
||||
|
DNS_H_QDCNT1 = 4, |
||||
|
DNS_H_QDCNT2 = 5, |
||||
|
DNS_H_QDCNT = DNS_H_QDCNT1, |
||||
|
#define dns_numqd(pkt) dns_get16((pkt)+4) |
||||
|
/* bytes 6:7: ancount, numanswers */ |
||||
|
DNS_H_ANCNT1 = 6, |
||||
|
DNS_H_ANCNT2 = 7, |
||||
|
DNS_H_ANCNT = DNS_H_ANCNT1, |
||||
|
#define dns_numan(pkt) dns_get16((pkt)+6) |
||||
|
/* bytes 8:9: nscount, numauthority */ |
||||
|
DNS_H_NSCNT1 = 8, |
||||
|
DNS_H_NSCNT2 = 9, |
||||
|
DNS_H_NSCNT = DNS_H_NSCNT1, |
||||
|
#define dns_numns(pkt) dns_get16((pkt)+8) |
||||
|
/* bytes 10:11: arcount, numadditional */ |
||||
|
DNS_H_ARCNT1 = 10, |
||||
|
DNS_H_ARCNT2 = 11, |
||||
|
DNS_H_ARCNT = DNS_H_ARCNT1, |
||||
|
#define dns_numar(pkt) dns_get16((pkt)+10) |
||||
|
#define dns_payload(pkt) ((pkt)+DNS_HSIZE) |
||||
|
}; |
||||
|
|
||||
|
/* packet buffer: start at pkt, end before pkte, current pos *curp.
|
||||
|
* extract a DN and set *curp to the next byte after DN in packet. |
||||
|
* return -1 on error, 0 if dnsiz is too small, or dnlen on ok. |
||||
|
*/ |
||||
|
UDNS_API int |
||||
|
dns_getdn(dnscc_t *pkt, dnscc_t **curp, dnscc_t *end, |
||||
|
dnsc_t *dn, unsigned dnsiz); |
||||
|
|
||||
|
/* skip the DN at position cur in packet ending before pkte,
|
||||
|
* return pointer to the next byte after the DN or NULL on error */ |
||||
|
UDNS_API dnscc_t * |
||||
|
dns_skipdn(dnscc_t *end, dnscc_t *cur); |
||||
|
|
||||
|
struct dns_rr { /* DNS Resource Record */ |
||||
|
dnsc_t dnsrr_dn[DNS_MAXDN]; /* the DN of the RR */ |
||||
|
enum dns_class dnsrr_cls; /* Class */ |
||||
|
enum dns_type dnsrr_typ; /* Type */ |
||||
|
unsigned dnsrr_ttl; /* Time-To-Live (TTL) */ |
||||
|
unsigned dnsrr_dsz; /* data size */ |
||||
|
dnscc_t *dnsrr_dptr; /* pointer to start of data */ |
||||
|
dnscc_t *dnsrr_dend; /* past end of data */ |
||||
|
}; |
||||
|
|
||||
|
struct dns_parse { /* RR/packet parsing state */ |
||||
|
dnscc_t *dnsp_pkt; /* start of the packet */ |
||||
|
dnscc_t *dnsp_end; /* end of the packet */ |
||||
|
dnscc_t *dnsp_cur; /* current packet position */ |
||||
|
dnscc_t *dnsp_ans; /* start of answer section */ |
||||
|
int dnsp_rrl; /* number of RRs left to go */ |
||||
|
int dnsp_nrr; /* RR count so far */ |
||||
|
unsigned dnsp_ttl; /* TTL value so far */ |
||||
|
dnscc_t *dnsp_qdn; /* the RR DN we're looking for */ |
||||
|
enum dns_class dnsp_qcls; /* RR class we're looking for or 0 */ |
||||
|
enum dns_type dnsp_qtyp; /* RR type we're looking for or 0 */ |
||||
|
dnsc_t dnsp_dnbuf[DNS_MAXDN]; /* domain buffer */ |
||||
|
}; |
||||
|
|
||||
|
/* initialize the parse structure */ |
||||
|
UDNS_API void |
||||
|
dns_initparse(struct dns_parse *p, dnscc_t *qdn, |
||||
|
dnscc_t *pkt, dnscc_t *cur, dnscc_t *end); |
||||
|
|
||||
|
/* search next RR, <0=error, 0=no more RRs, >0 = found. */ |
||||
|
UDNS_API int |
||||
|
dns_nextrr(struct dns_parse *p, struct dns_rr *rr); |
||||
|
|
||||
|
UDNS_API void |
||||
|
dns_rewind(struct dns_parse *p, dnscc_t *qdn); |
||||
|
|
||||
|
|
||||
|
/**************************************************************************/ |
||||
|
/**************** Resolver Context ****************************************/ |
||||
|
|
||||
|
/* default resolver context */ |
||||
|
UDNS_DATA_API extern struct dns_ctx dns_defctx; |
||||
|
|
||||
|
/* reset resolver context to default state, close it if open, drop queries */ |
||||
|
UDNS_API void |
||||
|
dns_reset(struct dns_ctx *ctx); |
||||
|
|
||||
|
/* reset resolver context and read in system configuration */ |
||||
|
UDNS_API int |
||||
|
dns_init(struct dns_ctx *ctx, int do_open); |
||||
|
|
||||
|
/* return new resolver context with the same settings as copy */ |
||||
|
UDNS_API struct dns_ctx * |
||||
|
dns_new(const struct dns_ctx *copy); |
||||
|
|
||||
|
/* free resolver context returned by dns_new(); all queries are dropped */ |
||||
|
UDNS_API void |
||||
|
dns_free(struct dns_ctx *ctx); |
||||
|
|
||||
|
/* add nameserver for a resolver context (or reset nslist if serv==NULL) */ |
||||
|
UDNS_API int |
||||
|
dns_add_serv(struct dns_ctx *ctx, const char *serv); |
||||
|
|
||||
|
/* add nameserver using struct sockaddr structure (with ports) */ |
||||
|
UDNS_API int |
||||
|
dns_add_serv_s(struct dns_ctx *ctx, const struct sockaddr *sa); |
||||
|
|
||||
|
/* add search list element for a resolver context (or reset it if srch==NULL) */ |
||||
|
UDNS_API int |
||||
|
dns_add_srch(struct dns_ctx *ctx, const char *srch); |
||||
|
|
||||
|
/* set options for a resolver context */ |
||||
|
UDNS_API int |
||||
|
dns_set_opts(struct dns_ctx *ctx, const char *opts); |
||||
|
|
||||
|
enum dns_opt { /* options */ |
||||
|
DNS_OPT_FLAGS, /* flags, DNS_F_XXX */ |
||||
|
DNS_OPT_TIMEOUT, /* timeout in secounds */ |
||||
|
DNS_OPT_NTRIES, /* number of retries */ |
||||
|
DNS_OPT_NDOTS, /* ndots */ |
||||
|
DNS_OPT_UDPSIZE, /* EDNS0 UDP size */ |
||||
|
DNS_OPT_PORT, /* port to use */ |
||||
|
}; |
||||
|
|
||||
|
/* set or get (if val<0) an option */ |
||||
|
UDNS_API int |
||||
|
dns_set_opt(struct dns_ctx *ctx, enum dns_opt opt, int val); |
||||
|
|
||||
|
enum dns_flags { |
||||
|
DNS_NOSRCH = 0x00010000, /* do not perform search */ |
||||
|
DNS_NORD = 0x00020000, /* request no recursion */ |
||||
|
DNS_AAONLY = 0x00040000, /* set AA flag in queries */ |
||||
|
}; |
||||
|
|
||||
|
/* set the debug function pointer */ |
||||
|
typedef void |
||||
|
(dns_dbgfn)(int code, const struct sockaddr *sa, unsigned salen, |
||||
|
dnscc_t *pkt, int plen, |
||||
|
const struct dns_query *q, void *data); |
||||
|
UDNS_API void |
||||
|
dns_set_dbgfn(struct dns_ctx *ctx, dns_dbgfn *dbgfn); |
||||
|
|
||||
|
/* open and return UDP socket */ |
||||
|
UDNS_API int |
||||
|
dns_open(struct dns_ctx *ctx); |
||||
|
|
||||
|
/* return UDP socket or -1 if not open */ |
||||
|
UDNS_API int |
||||
|
dns_sock(const struct dns_ctx *ctx); |
||||
|
|
||||
|
/* close the UDP socket */ |
||||
|
UDNS_API void |
||||
|
dns_close(struct dns_ctx *ctx); |
||||
|
|
||||
|
/* return number of requests queued */ |
||||
|
UDNS_API int |
||||
|
dns_active(const struct dns_ctx *ctx); |
||||
|
|
||||
|
/* return status of the last operation */ |
||||
|
UDNS_API int |
||||
|
dns_status(const struct dns_ctx *ctx); |
||||
|
UDNS_API void |
||||
|
dns_setstatus(struct dns_ctx *ctx, int status); |
||||
|
|
||||
|
/* handle I/O event on UDP socket */ |
||||
|
UDNS_API void |
||||
|
dns_ioevent(struct dns_ctx *ctx, time_t now); |
||||
|
|
||||
|
/* process any timeouts, return time in secounds to the
|
||||
|
* next timeout (or -1 if none) but not greather than maxwait */ |
||||
|
UDNS_API int |
||||
|
dns_timeouts(struct dns_ctx *ctx, int maxwait, time_t now); |
||||
|
|
||||
|
/* define timer requesting routine to use */ |
||||
|
typedef void dns_utm_fn(struct dns_ctx *ctx, int timeout, void *data); |
||||
|
UDNS_API void |
||||
|
dns_set_tmcbck(struct dns_ctx *ctx, dns_utm_fn *fn, void *data); |
||||
|
|
||||
|
/**************************************************************************/ |
||||
|
/**************** Making Queries ******************************************/ |
||||
|
|
||||
|
/* query callback routine */ |
||||
|
typedef void dns_query_fn(struct dns_ctx *ctx, void *result, void *data); |
||||
|
|
||||
|
/* query parse routine: raw DNS => application structure */ |
||||
|
typedef int |
||||
|
dns_parse_fn(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end, |
||||
|
void **res); |
||||
|
|
||||
|
enum dns_status { |
||||
|
DNS_E_NOERROR = 0, /* ok, not an error */ |
||||
|
DNS_E_TEMPFAIL = -1, /* timeout, SERVFAIL or similar */ |
||||
|
DNS_E_PROTOCOL = -2, /* got garbled reply */ |
||||
|
DNS_E_NXDOMAIN = -3, /* domain does not exists */ |
||||
|
DNS_E_NODATA = -4, /* domain exists but no data of reqd type */ |
||||
|
DNS_E_NOMEM = -5, /* out of memory while processing */ |
||||
|
DNS_E_BADQUERY = -6 /* the query is malformed */ |
||||
|
}; |
||||
|
|
||||
|
/* submit generic DN query */ |
||||
|
UDNS_API struct dns_query * |
||||
|
dns_submit_dn(struct dns_ctx *ctx, |
||||
|
dnscc_t *dn, int qcls, int qtyp, int flags, |
||||
|
dns_parse_fn *parse, dns_query_fn *cbck, void *data); |
||||
|
/* submit generic name query */ |
||||
|
UDNS_API struct dns_query * |
||||
|
dns_submit_p(struct dns_ctx *ctx, |
||||
|
const char *name, int qcls, int qtyp, int flags, |
||||
|
dns_parse_fn *parse, dns_query_fn *cbck, void *data); |
||||
|
|
||||
|
/* cancel the given async query in progress */ |
||||
|
UDNS_API int |
||||
|
dns_cancel(struct dns_ctx *ctx, struct dns_query *q); |
||||
|
|
||||
|
/* resolve a generic query, return the answer */ |
||||
|
UDNS_API void * |
||||
|
dns_resolve_dn(struct dns_ctx *ctx, |
||||
|
dnscc_t *qdn, int qcls, int qtyp, int flags, |
||||
|
dns_parse_fn *parse); |
||||
|
UDNS_API void * |
||||
|
dns_resolve_p(struct dns_ctx *ctx, |
||||
|
const char *qname, int qcls, int qtyp, int flags, |
||||
|
dns_parse_fn *parse); |
||||
|
UDNS_API void * |
||||
|
dns_resolve(struct dns_ctx *ctx, struct dns_query *q); |
||||
|
|
||||
|
|
||||
|
/* Specific RR handlers */ |
||||
|
|
||||
|
#define dns_rr_common(prefix) \ |
||||
|
char *prefix##_cname; /* canonical name */ \ |
||||
|
char *prefix##_qname; /* original query name */ \ |
||||
|
unsigned prefix##_ttl; /* TTL value */ \ |
||||
|
int prefix##_nrr /* number of records */ |
||||
|
|
||||
|
struct dns_rr_null { /* NULL RRset, aka RRset template */ |
||||
|
dns_rr_common(dnsn); |
||||
|
}; |
||||
|
|
||||
|
UDNS_API int |
||||
|
dns_stdrr_size(const struct dns_parse *p); |
||||
|
UDNS_API void * |
||||
|
dns_stdrr_finish(struct dns_rr_null *ret, char *cp, const struct dns_parse *p); |
||||
|
|
||||
|
struct dns_rr_a4 { /* the A RRset */ |
||||
|
dns_rr_common(dnsa4); |
||||
|
struct in_addr *dnsa4_addr; /* array of addresses, naddr elements */ |
||||
|
}; |
||||
|
|
||||
|
UDNS_API dns_parse_fn dns_parse_a4; /* A RR parsing routine */ |
||||
|
typedef void /* A query callback routine */ |
||||
|
dns_query_a4_fn(struct dns_ctx *ctx, struct dns_rr_a4 *result, void *data); |
||||
|
|
||||
|
/* submit A IN query */ |
||||
|
UDNS_API struct dns_query * |
||||
|
dns_submit_a4(struct dns_ctx *ctx, const char *name, int flags, |
||||
|
dns_query_a4_fn *cbck, void *data); |
||||
|
|
||||
|
/* resolve A IN query */ |
||||
|
UDNS_API struct dns_rr_a4 * |
||||
|
dns_resolve_a4(struct dns_ctx *ctx, const char *name, int flags); |
||||
|
|
||||
|
|
||||
|
struct dns_rr_a6 { /* the AAAA RRset */ |
||||
|
dns_rr_common(dnsa6); |
||||
|
struct in6_addr *dnsa6_addr; /* array of addresses, naddr elements */ |
||||
|
}; |
||||
|
|
||||
|
UDNS_API dns_parse_fn dns_parse_a6; /* A RR parsing routine */ |
||||
|
typedef void /* A query callback routine */ |
||||
|
dns_query_a6_fn(struct dns_ctx *ctx, struct dns_rr_a6 *result, void *data); |
||||
|
|
||||
|
/* submit AAAA IN query */ |
||||
|
UDNS_API struct dns_query * |
||||
|
dns_submit_a6(struct dns_ctx *ctx, const char *name, int flags, |
||||
|
dns_query_a6_fn *cbck, void *data); |
||||
|
|
||||
|
/* resolve AAAA IN query */ |
||||
|
UDNS_API struct dns_rr_a6 * |
||||
|
dns_resolve_a6(struct dns_ctx *ctx, const char *name, int flags); |
||||
|
|
||||
|
|
||||
|
struct dns_rr_ptr { /* the PTR RRset */ |
||||
|
dns_rr_common(dnsptr); |
||||
|
char **dnsptr_ptr; /* array of PTRs */ |
||||
|
}; |
||||
|
|
||||
|
UDNS_API dns_parse_fn dns_parse_ptr; /* PTR RR parsing routine */ |
||||
|
typedef void /* PTR query callback */ |
||||
|
dns_query_ptr_fn(struct dns_ctx *ctx, struct dns_rr_ptr *result, void *data); |
||||
|
/* submit PTR IN in-addr.arpa query */ |
||||
|
UDNS_API struct dns_query * |
||||
|
dns_submit_a4ptr(struct dns_ctx *ctx, const struct in_addr *addr, |
||||
|
dns_query_ptr_fn *cbck, void *data); |
||||
|
/* resolve PTR IN in-addr.arpa query */ |
||||
|
UDNS_API struct dns_rr_ptr * |
||||
|
dns_resolve_a4ptr(struct dns_ctx *ctx, const struct in_addr *addr); |
||||
|
|
||||
|
/* the same as above, but for ip6.arpa */ |
||||
|
UDNS_API struct dns_query * |
||||
|
dns_submit_a6ptr(struct dns_ctx *ctx, const struct in6_addr *addr, |
||||
|
dns_query_ptr_fn *cbck, void *data); |
||||
|
UDNS_API struct dns_rr_ptr * |
||||
|
dns_resolve_a6ptr(struct dns_ctx *ctx, const struct in6_addr *addr); |
||||
|
|
||||
|
|
||||
|
struct dns_mx { /* single MX RR */ |
||||
|
int priority; /* MX priority */ |
||||
|
char *name; /* MX name */ |
||||
|
}; |
||||
|
struct dns_rr_mx { /* the MX RRset */ |
||||
|
dns_rr_common(dnsmx); |
||||
|
struct dns_mx *dnsmx_mx; /* array of MXes */ |
||||
|
}; |
||||
|
UDNS_API dns_parse_fn dns_parse_mx; /* MX RR parsing routine */ |
||||
|
typedef void /* MX RR callback */ |
||||
|
dns_query_mx_fn(struct dns_ctx *ctx, struct dns_rr_mx *result, void *data); |
||||
|
/* submit MX IN query */ |
||||
|
UDNS_API struct dns_query * |
||||
|
dns_submit_mx(struct dns_ctx *ctx, const char *name, int flags, |
||||
|
dns_query_mx_fn *cbck, void *data); |
||||
|
/* resolve MX IN query */ |
||||
|
UDNS_API struct dns_rr_mx * |
||||
|
dns_resolve_mx(struct dns_ctx *ctx, const char *name, int flags); |
||||
|
|
||||
|
|
||||
|
struct dns_txt { /* single TXT record */ |
||||
|
int len; /* length of the text */ |
||||
|
dnsc_t *txt; /* pointer to text buffer. May contain nulls. */ |
||||
|
}; |
||||
|
struct dns_rr_txt { /* the TXT RRset */ |
||||
|
dns_rr_common(dnstxt); |
||||
|
struct dns_txt *dnstxt_txt; /* array of TXT records */ |
||||
|
}; |
||||
|
UDNS_API dns_parse_fn dns_parse_txt; /* TXT RR parsing routine */ |
||||
|
typedef void /* TXT RR callback */ |
||||
|
dns_query_txt_fn(struct dns_ctx *ctx, struct dns_rr_txt *result, void *data); |
||||
|
/* submit TXT query */ |
||||
|
UDNS_API struct dns_query * |
||||
|
dns_submit_txt(struct dns_ctx *ctx, const char *name, int qcls, int flags, |
||||
|
dns_query_txt_fn *cbck, void *data); |
||||
|
/* resolve TXT query */ |
||||
|
UDNS_API struct dns_rr_txt * |
||||
|
dns_resolve_txt(struct dns_ctx *ctx, const char *name, int qcls, int flags); |
||||
|
|
||||
|
|
||||
|
struct dns_srv { /* single SRV RR */ |
||||
|
int priority; /* SRV priority */ |
||||
|
int weight; /* SRV weight */ |
||||
|
int port; /* SRV port */ |
||||
|
char *name; /* SRV name */ |
||||
|
}; |
||||
|
struct dns_rr_srv { /* the SRV RRset */ |
||||
|
dns_rr_common(dnssrv); |
||||
|
struct dns_srv *dnssrv_srv; /* array of SRVes */ |
||||
|
}; |
||||
|
UDNS_API dns_parse_fn dns_parse_srv; /* SRV RR parsing routine */ |
||||
|
typedef void /* SRV RR callback */ |
||||
|
dns_query_srv_fn(struct dns_ctx *ctx, struct dns_rr_srv *result, void *data); |
||||
|
/* submit SRV IN query */ |
||||
|
UDNS_API struct dns_query * |
||||
|
dns_submit_srv(struct dns_ctx *ctx, |
||||
|
const char *name, const char *srv, const char *proto, |
||||
|
int flags, dns_query_srv_fn *cbck, void *data); |
||||
|
/* resolve SRV IN query */ |
||||
|
UDNS_API struct dns_rr_srv * |
||||
|
dns_resolve_srv(struct dns_ctx *ctx, |
||||
|
const char *name, const char *srv, const char *proto, |
||||
|
int flags); |
||||
|
|
||||
|
/* NAPTR (RFC3403) RR type */ |
||||
|
struct dns_naptr { /* single NAPTR RR */ |
||||
|
int order; /* NAPTR order */ |
||||
|
int preference; /* NAPTR preference */ |
||||
|
char *flags; /* NAPTR flags */ |
||||
|
char *service; /* NAPTR service */ |
||||
|
char *regexp; /* NAPTR regexp */ |
||||
|
char *replacement; /* NAPTR replacement */ |
||||
|
}; |
||||
|
|
||||
|
struct dns_rr_naptr { /* the NAPTR RRset */ |
||||
|
dns_rr_common(dnsnaptr); |
||||
|
struct dns_naptr *dnsnaptr_naptr; /* array of NAPTRes */ |
||||
|
}; |
||||
|
UDNS_API dns_parse_fn dns_parse_naptr; /* NAPTR RR parsing routine */ |
||||
|
typedef void /* NAPTR RR callback */ |
||||
|
dns_query_naptr_fn(struct dns_ctx *ctx, |
||||
|
struct dns_rr_naptr *result, void *data); |
||||
|
/* submit NAPTR IN query */ |
||||
|
UDNS_API struct dns_query * |
||||
|
dns_submit_naptr(struct dns_ctx *ctx, const char *name, int flags, |
||||
|
dns_query_naptr_fn *cbck, void *data); |
||||
|
/* resolve NAPTR IN query */ |
||||
|
UDNS_API struct dns_rr_naptr * |
||||
|
dns_resolve_naptr(struct dns_ctx *ctx, const char *name, int flags); |
||||
|
|
||||
|
|
||||
|
UDNS_API struct dns_query * |
||||
|
dns_submit_a4dnsbl(struct dns_ctx *ctx, |
||||
|
const struct in_addr *addr, const char *dnsbl, |
||||
|
dns_query_a4_fn *cbck, void *data); |
||||
|
UDNS_API struct dns_query * |
||||
|
dns_submit_a4dnsbl_txt(struct dns_ctx *ctx, |
||||
|
const struct in_addr *addr, const char *dnsbl, |
||||
|
dns_query_txt_fn *cbck, void *data); |
||||
|
UDNS_API struct dns_rr_a4 * |
||||
|
dns_resolve_a4dnsbl(struct dns_ctx *ctx, |
||||
|
const struct in_addr *addr, const char *dnsbl); |
||||
|
UDNS_API struct dns_rr_txt * |
||||
|
dns_resolve_a4dnsbl_txt(struct dns_ctx *ctx, |
||||
|
const struct in_addr *addr, const char *dnsbl); |
||||
|
|
||||
|
UDNS_API struct dns_query * |
||||
|
dns_submit_a6dnsbl(struct dns_ctx *ctx, |
||||
|
const struct in6_addr *addr, const char *dnsbl, |
||||
|
dns_query_a4_fn *cbck, void *data); |
||||
|
UDNS_API struct dns_query * |
||||
|
dns_submit_a6dnsbl_txt(struct dns_ctx *ctx, |
||||
|
const struct in6_addr *addr, const char *dnsbl, |
||||
|
dns_query_txt_fn *cbck, void *data); |
||||
|
UDNS_API struct dns_rr_a4 * |
||||
|
dns_resolve_a6dnsbl(struct dns_ctx *ctx, |
||||
|
const struct in6_addr *addr, const char *dnsbl); |
||||
|
UDNS_API struct dns_rr_txt * |
||||
|
dns_resolve_a6dnsbl_txt(struct dns_ctx *ctx, |
||||
|
const struct in6_addr *addr, const char *dnsbl); |
||||
|
|
||||
|
UDNS_API struct dns_query * |
||||
|
dns_submit_rhsbl(struct dns_ctx *ctx, |
||||
|
const char *name, const char *rhsbl, |
||||
|
dns_query_a4_fn *cbck, void *data); |
||||
|
UDNS_API struct dns_query * |
||||
|
dns_submit_rhsbl_txt(struct dns_ctx *ctx, |
||||
|
const char *name, const char *rhsbl, |
||||
|
dns_query_txt_fn *cbck, void *data); |
||||
|
UDNS_API struct dns_rr_a4 * |
||||
|
dns_resolve_rhsbl(struct dns_ctx *ctx, const char *name, const char *rhsbl); |
||||
|
UDNS_API struct dns_rr_txt * |
||||
|
dns_resolve_rhsbl_txt(struct dns_ctx *ctx, const char *name, const char *rhsbl); |
||||
|
|
||||
|
/**************************************************************************/ |
||||
|
/**************** Names, Names ********************************************/ |
||||
|
|
||||
|
struct dns_nameval { |
||||
|
int val; |
||||
|
const char *name; |
||||
|
}; |
||||
|
|
||||
|
UDNS_DATA_API extern const struct dns_nameval dns_classtab[]; |
||||
|
UDNS_DATA_API extern const struct dns_nameval dns_typetab[]; |
||||
|
UDNS_DATA_API extern const struct dns_nameval dns_rcodetab[]; |
||||
|
UDNS_API int |
||||
|
dns_findname(const struct dns_nameval *nv, const char *name); |
||||
|
#define dns_findclassname(cls) dns_findname(dns_classtab, (cls)) |
||||
|
#define dns_findtypename(type) dns_findname(dns_typetab, (type)) |
||||
|
#define dns_findrcodename(rcode) dns_findname(dns_rcodetab, (rcode)) |
||||
|
|
||||
|
UDNS_API const char *dns_classname(enum dns_class cls); |
||||
|
UDNS_API const char *dns_typename(enum dns_type type); |
||||
|
UDNS_API const char *dns_rcodename(enum dns_rcode rcode); |
||||
|
const char *_dns_format_code(char *buf, const char *prefix, int code); |
||||
|
|
||||
|
UDNS_API const char *dns_strerror(int errnum); |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} /* extern "C" */ |
||||
|
#endif |
||||
|
|
||||
|
#endif /* include guard */ |
@ -0,0 +1,50 @@ |
|||||
|
/* $Id: udns_XtoX.c,v 1.1 2007/01/07 22:20:39 mjt Exp $
|
||||
|
udns_ntop() and udns_pton() routines, which are either |
||||
|
- wrappers for inet_ntop() and inet_pton() or |
||||
|
- reimplementations of those routines. |
||||
|
|
||||
|
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru> |
||||
|
This file is part of UDNS library, an async DNS stub resolver. |
||||
|
|
||||
|
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.1 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, in file named COPYING.LGPL; if not, |
||||
|
write to the Free Software Foundation, Inc., 59 Temple Place, |
||||
|
Suite 330, Boston, MA 02111-1307 USA |
||||
|
|
||||
|
*/ |
||||
|
|
||||
|
#ifdef HAVE_CONFIG_H |
||||
|
# include "config.h" |
||||
|
#endif |
||||
|
#include "udns.h" |
||||
|
|
||||
|
#ifdef HAVE_INET_PTON_NTOP |
||||
|
|
||||
|
#include <sys/types.h> |
||||
|
#include <sys/socket.h> |
||||
|
#include <arpa/inet.h> |
||||
|
|
||||
|
const char *dns_ntop(int af, const void *src, char *dst, int size) { |
||||
|
return inet_ntop(af, src, dst, size); |
||||
|
} |
||||
|
|
||||
|
int dns_pton(int af, const char *src, void *dst) { |
||||
|
return inet_pton(af, src, dst); |
||||
|
} |
||||
|
|
||||
|
#else |
||||
|
|
||||
|
#define inet_XtoX_prefix udns_ |
||||
|
#include "inet_XtoX.c" |
||||
|
|
||||
|
#endif |
@ -0,0 +1,160 @@ |
|||||
|
/* $Id: udns_bl.c,v 1.10 2005/09/12 10:55:21 mjt Exp $
|
||||
|
DNSBL stuff |
||||
|
|
||||
|
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru> |
||||
|
This file is part of UDNS library, an async DNS stub resolver. |
||||
|
|
||||
|
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.1 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, in file named COPYING.LGPL; if not, |
||||
|
write to the Free Software Foundation, Inc., 59 Temple Place, |
||||
|
Suite 330, Boston, MA 02111-1307 USA |
||||
|
|
||||
|
*/ |
||||
|
|
||||
|
#include "udns.h" |
||||
|
#ifndef NULL |
||||
|
# define NULL 0 |
||||
|
#endif |
||||
|
|
||||
|
struct dns_query * |
||||
|
dns_submit_a4dnsbl(struct dns_ctx *ctx, |
||||
|
const struct in_addr *addr, const char *dnsbl, |
||||
|
dns_query_a4_fn *cbck, void *data) { |
||||
|
dnsc_t dn[DNS_MAXDN]; |
||||
|
if (dns_a4ptodn(addr, dnsbl, dn, sizeof(dn)) <= 0) { |
||||
|
dns_setstatus(ctx, DNS_E_BADQUERY); |
||||
|
return NULL; |
||||
|
} |
||||
|
return |
||||
|
dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_A, DNS_NOSRCH, |
||||
|
dns_parse_a4, (dns_query_fn*)cbck, data); |
||||
|
} |
||||
|
|
||||
|
struct dns_query * |
||||
|
dns_submit_a4dnsbl_txt(struct dns_ctx *ctx, |
||||
|
const struct in_addr *addr, const char *dnsbl, |
||||
|
dns_query_txt_fn *cbck, void *data) { |
||||
|
dnsc_t dn[DNS_MAXDN]; |
||||
|
if (dns_a4ptodn(addr, dnsbl, dn, sizeof(dn)) <= 0) { |
||||
|
dns_setstatus(ctx, DNS_E_BADQUERY); |
||||
|
return NULL; |
||||
|
} |
||||
|
return |
||||
|
dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_TXT, DNS_NOSRCH, |
||||
|
dns_parse_txt, (dns_query_fn*)cbck, data); |
||||
|
} |
||||
|
|
||||
|
struct dns_rr_a4 * |
||||
|
dns_resolve_a4dnsbl(struct dns_ctx *ctx, |
||||
|
const struct in_addr *addr, const char *dnsbl) { |
||||
|
return (struct dns_rr_a4 *) |
||||
|
dns_resolve(ctx, dns_submit_a4dnsbl(ctx, addr, dnsbl, 0, 0)); |
||||
|
} |
||||
|
|
||||
|
struct dns_rr_txt * |
||||
|
dns_resolve_a4dnsbl_txt(struct dns_ctx *ctx, |
||||
|
const struct in_addr *addr, const char *dnsbl) { |
||||
|
return (struct dns_rr_txt *) |
||||
|
dns_resolve(ctx, dns_submit_a4dnsbl_txt(ctx, addr, dnsbl, 0, 0)); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
struct dns_query * |
||||
|
dns_submit_a6dnsbl(struct dns_ctx *ctx, |
||||
|
const struct in6_addr *addr, const char *dnsbl, |
||||
|
dns_query_a4_fn *cbck, void *data) { |
||||
|
dnsc_t dn[DNS_MAXDN]; |
||||
|
if (dns_a6ptodn(addr, dnsbl, dn, sizeof(dn)) <= 0) { |
||||
|
dns_setstatus(ctx, DNS_E_BADQUERY); |
||||
|
return NULL; |
||||
|
} |
||||
|
return |
||||
|
dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_A, DNS_NOSRCH, |
||||
|
dns_parse_a4, (dns_query_fn*)cbck, data); |
||||
|
} |
||||
|
|
||||
|
struct dns_query * |
||||
|
dns_submit_a6dnsbl_txt(struct dns_ctx *ctx, |
||||
|
const struct in6_addr *addr, const char *dnsbl, |
||||
|
dns_query_txt_fn *cbck, void *data) { |
||||
|
dnsc_t dn[DNS_MAXDN]; |
||||
|
if (dns_a6ptodn(addr, dnsbl, dn, sizeof(dn)) <= 0) { |
||||
|
dns_setstatus(ctx, DNS_E_BADQUERY); |
||||
|
return NULL; |
||||
|
} |
||||
|
return |
||||
|
dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_TXT, DNS_NOSRCH, |
||||
|
dns_parse_txt, (dns_query_fn*)cbck, data); |
||||
|
} |
||||
|
|
||||
|
struct dns_rr_a4 * |
||||
|
dns_resolve_a6dnsbl(struct dns_ctx *ctx, |
||||
|
const struct in6_addr *addr, const char *dnsbl) { |
||||
|
return (struct dns_rr_a4 *) |
||||
|
dns_resolve(ctx, dns_submit_a6dnsbl(ctx, addr, dnsbl, 0, 0)); |
||||
|
} |
||||
|
|
||||
|
struct dns_rr_txt * |
||||
|
dns_resolve_a6dnsbl_txt(struct dns_ctx *ctx, |
||||
|
const struct in6_addr *addr, const char *dnsbl) { |
||||
|
return (struct dns_rr_txt *) |
||||
|
dns_resolve(ctx, dns_submit_a6dnsbl_txt(ctx, addr, dnsbl, 0, 0)); |
||||
|
} |
||||
|
|
||||
|
static int |
||||
|
dns_rhsbltodn(const char *name, const char *rhsbl, dnsc_t dn[DNS_MAXDN]) |
||||
|
{ |
||||
|
int l = dns_sptodn(name, dn, DNS_MAXDN); |
||||
|
if (l <= 0) return 0; |
||||
|
l = dns_sptodn(rhsbl, dn+l-1, DNS_MAXDN-l+1); |
||||
|
if (l <= 0) return 0; |
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
struct dns_query * |
||||
|
dns_submit_rhsbl(struct dns_ctx *ctx, const char *name, const char *rhsbl, |
||||
|
dns_query_a4_fn *cbck, void *data) { |
||||
|
dnsc_t dn[DNS_MAXDN]; |
||||
|
if (!dns_rhsbltodn(name, rhsbl, dn)) { |
||||
|
dns_setstatus(ctx, DNS_E_BADQUERY); |
||||
|
return NULL; |
||||
|
} |
||||
|
return |
||||
|
dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_A, DNS_NOSRCH, |
||||
|
dns_parse_a4, (dns_query_fn*)cbck, data); |
||||
|
} |
||||
|
struct dns_query * |
||||
|
dns_submit_rhsbl_txt(struct dns_ctx *ctx, const char *name, const char *rhsbl, |
||||
|
dns_query_txt_fn *cbck, void *data) { |
||||
|
dnsc_t dn[DNS_MAXDN]; |
||||
|
if (!dns_rhsbltodn(name, rhsbl, dn)) { |
||||
|
dns_setstatus(ctx, DNS_E_BADQUERY); |
||||
|
return NULL; |
||||
|
} |
||||
|
return |
||||
|
dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_TXT, DNS_NOSRCH, |
||||
|
dns_parse_txt, (dns_query_fn*)cbck, data); |
||||
|
} |
||||
|
|
||||
|
struct dns_rr_a4 * |
||||
|
dns_resolve_rhsbl(struct dns_ctx *ctx, const char *name, const char *rhsbl) { |
||||
|
return (struct dns_rr_a4*) |
||||
|
dns_resolve(ctx, dns_submit_rhsbl(ctx, name, rhsbl, 0, 0)); |
||||
|
} |
||||
|
|
||||
|
struct dns_rr_txt * |
||||
|
dns_resolve_rhsbl_txt(struct dns_ctx *ctx, const char *name, const char *rhsbl) |
||||
|
{ |
||||
|
return (struct dns_rr_txt*) |
||||
|
dns_resolve(ctx, dns_submit_rhsbl_txt(ctx, name, rhsbl, 0, 0)); |
||||
|
} |
@ -0,0 +1,382 @@ |
|||||
|
/* $Id: udns_dn.c,v 1.7 2006/11/28 22:45:20 mjt Exp $
|
||||
|
domain names manipulation routines |
||||
|
|
||||
|
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru> |
||||
|
This file is part of UDNS library, an async DNS stub resolver. |
||||
|
|
||||
|
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.1 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, in file named COPYING.LGPL; if not, |
||||
|
write to the Free Software Foundation, Inc., 59 Temple Place, |
||||
|
Suite 330, Boston, MA 02111-1307 USA |
||||
|
|
||||
|
*/ |
||||
|
|
||||
|
#include <string.h> |
||||
|
#include "udns.h" |
||||
|
|
||||
|
unsigned dns_dnlen(dnscc_t *dn) { |
||||
|
register dnscc_t *d = dn; |
||||
|
while(*d) |
||||
|
d += 1 + *d; |
||||
|
return (unsigned)(d - dn) + 1; |
||||
|
} |
||||
|
|
||||
|
unsigned dns_dnlabels(register dnscc_t *dn) { |
||||
|
register unsigned l = 0; |
||||
|
while(*dn) |
||||
|
++l, dn += 1 + *dn; |
||||
|
return l; |
||||
|
} |
||||
|
|
||||
|
unsigned dns_dnequal(register dnscc_t *dn1, register dnscc_t *dn2) { |
||||
|
register unsigned c; |
||||
|
dnscc_t *dn = dn1; |
||||
|
for(;;) { |
||||
|
if ((c = *dn1++) != *dn2++) |
||||
|
return 0; |
||||
|
if (!c) |
||||
|
return (unsigned)(dn1 - dn); |
||||
|
while(c--) { |
||||
|
if (DNS_DNLC(*dn1) != DNS_DNLC(*dn2)) |
||||
|
return 0; |
||||
|
++dn1; ++dn2; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
unsigned |
||||
|
dns_dntodn(dnscc_t *sdn, dnsc_t *ddn, unsigned ddnsiz) { |
||||
|
unsigned sdnlen = dns_dnlen(sdn); |
||||
|
if (ddnsiz < sdnlen) |
||||
|
return 0; |
||||
|
memcpy(ddn, sdn, sdnlen); |
||||
|
return sdnlen; |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
dns_ptodn(const char *name, unsigned namelen, |
||||
|
dnsc_t *dn, unsigned dnsiz, int *isabs) |
||||
|
{ |
||||
|
dnsc_t *dp; /* current position in dn (len byte first) */ |
||||
|
dnsc_t *const de /* end of dn: last byte that can be filled up */ |
||||
|
= dn + (dnsiz >= DNS_MAXDN ? DNS_MAXDN : dnsiz) - 1; |
||||
|
dnscc_t *np = (dnscc_t *)name; |
||||
|
dnscc_t *ne = np + (namelen ? namelen : strlen((char*)np)); |
||||
|
dnsc_t *llab; /* start of last label (llab[-1] will be length) */ |
||||
|
unsigned c; /* next input character, or length of last label */ |
||||
|
|
||||
|
if (!dnsiz) |
||||
|
return 0; |
||||
|
dp = llab = dn + 1; |
||||
|
|
||||
|
while(np < ne) { |
||||
|
|
||||
|
if (*np == '.') { /* label delimiter */ |
||||
|
c = dp - llab; /* length of the label */ |
||||
|
if (!c) { /* empty label */ |
||||
|
if (np == (dnscc_t *)name && np + 1 == ne) { |
||||
|
/* special case for root dn, aka `.' */ |
||||
|
++np; |
||||
|
break; |
||||
|
} |
||||
|
return -1; /* zero label */ |
||||
|
} |
||||
|
if (c > DNS_MAXLABEL) |
||||
|
return -1; /* label too long */ |
||||
|
llab[-1] = (dnsc_t)c; /* update len of last label */ |
||||
|
llab = ++dp; /* start new label, llab[-1] will be len of it */ |
||||
|
++np; |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
/* check whenever we may put out one more byte */ |
||||
|
if (dp >= de) /* too long? */ |
||||
|
return dnsiz >= DNS_MAXDN ? -1 : 0; |
||||
|
if (*np != '\\') { /* non-escape, simple case */ |
||||
|
*dp++ = *np++; |
||||
|
continue; |
||||
|
} |
||||
|
/* handle \-style escape */ |
||||
|
/* note that traditionally, domain names (gethostbyname etc)
|
||||
|
* used decimal \dd notation, not octal \ooo (RFC1035), so |
||||
|
* we're following this tradition here. |
||||
|
*/ |
||||
|
if (++np == ne) |
||||
|
return -1; /* bad escape */ |
||||
|
else if (*np >= '0' && *np <= '9') { /* decimal number */ |
||||
|
/* we allow not only exactly 3 digits as per RFC1035,
|
||||
|
* but also 2 or 1, for better usability. */ |
||||
|
c = *np++ - '0'; |
||||
|
if (np < ne && *np >= '0' && *np <= '9') { /* 2digits */ |
||||
|
c = c * 10 + *np++ - '0'; |
||||
|
if (np < ne && *np >= '0' && *np <= '9') { |
||||
|
c = c * 10 + *np++ - '0'; |
||||
|
if (c > 255) |
||||
|
return -1; /* bad escape */ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
c = *np++; |
||||
|
*dp++ = (dnsc_t)c; /* place next out byte */ |
||||
|
} |
||||
|
|
||||
|
if ((c = dp - llab) > DNS_MAXLABEL) |
||||
|
return -1; /* label too long */ |
||||
|
if ((llab[-1] = (dnsc_t)c) != 0) { |
||||
|
*dp++ = 0; |
||||
|
if (isabs) |
||||
|
*isabs = 0; |
||||
|
} |
||||
|
else if (isabs) |
||||
|
*isabs = 1; |
||||
|
|
||||
|
return dp - dn; |
||||
|
} |
||||
|
|
||||
|
dnscc_t dns_inaddr_arpa_dn[14] = "\07in-addr\04arpa"; |
||||
|
|
||||
|
dnsc_t * |
||||
|
dns_a4todn_(const struct in_addr *addr, dnsc_t *dn, dnsc_t *dne) { |
||||
|
dnsc_t *p; |
||||
|
unsigned n; |
||||
|
dnscc_t *s = ((dnscc_t *)addr) + 4; |
||||
|
while(--s >= (dnscc_t *)addr) { |
||||
|
n = *s; |
||||
|
p = dn + 1; |
||||
|
if (n > 99) { |
||||
|
if (p + 2 > dne) return 0; |
||||
|
*p++ = n / 100 + '0'; |
||||
|
*p++ = (n % 100 / 10) + '0'; |
||||
|
*p = n % 10 + '0'; |
||||
|
} |
||||
|
else if (n > 9) { |
||||
|
if (p + 1 > dne) return 0; |
||||
|
*p++ = n / 10 + '0'; |
||||
|
*p = n % 10 + '0'; |
||||
|
} |
||||
|
else { |
||||
|
if (p > dne) return 0; |
||||
|
*p = n + '0'; |
||||
|
} |
||||
|
*dn = p - dn; |
||||
|
dn = p + 1; |
||||
|
} |
||||
|
return dn; |
||||
|
} |
||||
|
|
||||
|
int dns_a4todn(const struct in_addr *addr, dnscc_t *tdn, |
||||
|
dnsc_t *dn, unsigned dnsiz) { |
||||
|
dnsc_t *dne = dn + (dnsiz > DNS_MAXDN ? DNS_MAXDN : dnsiz); |
||||
|
dnsc_t *p; |
||||
|
unsigned l; |
||||
|
p = dns_a4todn_(addr, dn, dne); |
||||
|
if (!p) return 0; |
||||
|
if (!tdn) |
||||
|
tdn = dns_inaddr_arpa_dn; |
||||
|
l = dns_dnlen(tdn); |
||||
|
if (p + l > dne) return dnsiz >= DNS_MAXDN ? -1 : 0; |
||||
|
memcpy(p, tdn, l); |
||||
|
return (p + l) - dn; |
||||
|
} |
||||
|
|
||||
|
int dns_a4ptodn(const struct in_addr *addr, const char *tname, |
||||
|
dnsc_t *dn, unsigned dnsiz) { |
||||
|
dnsc_t *p; |
||||
|
int r; |
||||
|
if (!tname) |
||||
|
return dns_a4todn(addr, NULL, dn, dnsiz); |
||||
|
p = dns_a4todn_(addr, dn, dn + dnsiz); |
||||
|
if (!p) return 0; |
||||
|
r = dns_sptodn(tname, p, dnsiz - (p - dn)); |
||||
|
return r != 0 ? r : dnsiz >= DNS_MAXDN ? -1 : 0; |
||||
|
} |
||||
|
|
||||
|
dnscc_t dns_ip6_arpa_dn[10] = "\03ip6\04arpa"; |
||||
|
|
||||
|
dnsc_t * |
||||
|
dns_a6todn_(const struct in6_addr *addr, dnsc_t *dn, dnsc_t *dne) { |
||||
|
unsigned n; |
||||
|
dnscc_t *s = ((dnscc_t *)addr) + 16; |
||||
|
if (dn + 64 > dne) return 0; |
||||
|
while(--s >= (dnscc_t *)addr) { |
||||
|
*dn++ = 1; |
||||
|
n = *s & 0x0f; |
||||
|
*dn++ = n > 9 ? n + 'a' - 10 : n + '0'; |
||||
|
*dn++ = 1; |
||||
|
n = *s >> 4; |
||||
|
*dn++ = n > 9 ? n + 'a' - 10 : n + '0'; |
||||
|
} |
||||
|
return dn; |
||||
|
} |
||||
|
|
||||
|
int dns_a6todn(const struct in6_addr *addr, dnscc_t *tdn, |
||||
|
dnsc_t *dn, unsigned dnsiz) { |
||||
|
dnsc_t *dne = dn + (dnsiz > DNS_MAXDN ? DNS_MAXDN : dnsiz); |
||||
|
dnsc_t *p; |
||||
|
unsigned l; |
||||
|
p = dns_a6todn_(addr, dn, dne); |
||||
|
if (!p) return 0; |
||||
|
if (!tdn) |
||||
|
tdn = dns_ip6_arpa_dn; |
||||
|
l = dns_dnlen(tdn); |
||||
|
if (p + l > dne) return dnsiz >= DNS_MAXDN ? -1 : 0; |
||||
|
memcpy(p, tdn, l); |
||||
|
return (p + l) - dn; |
||||
|
} |
||||
|
|
||||
|
int dns_a6ptodn(const struct in6_addr *addr, const char *tname, |
||||
|
dnsc_t *dn, unsigned dnsiz) { |
||||
|
dnsc_t *p; |
||||
|
int r; |
||||
|
if (!tname) |
||||
|
return dns_a6todn(addr, NULL, dn, dnsiz); |
||||
|
p = dns_a6todn_(addr, dn, dn + dnsiz); |
||||
|
if (!p) return 0; |
||||
|
r = dns_sptodn(tname, p, dnsiz - (p - dn)); |
||||
|
return r != 0 ? r : dnsiz >= DNS_MAXDN ? -1 : 0; |
||||
|
} |
||||
|
|
||||
|
/* return size of buffer required to convert the dn into asciiz string.
|
||||
|
* Keep in sync with dns_dntop() below. |
||||
|
*/ |
||||
|
unsigned dns_dntop_size(dnscc_t *dn) { |
||||
|
unsigned size = 0; /* the size reqd */ |
||||
|
dnscc_t *le; /* label end */ |
||||
|
|
||||
|
while(*dn) { |
||||
|
/* *dn is the length of the next label, non-zero */ |
||||
|
if (size) |
||||
|
++size; /* for the dot */ |
||||
|
le = dn + *dn + 1; |
||||
|
++dn; |
||||
|
do { |
||||
|
switch(*dn) { |
||||
|
case '.': |
||||
|
case '\\': |
||||
|
/* Special modifiers in zone files. */ |
||||
|
case '"': |
||||
|
case ';': |
||||
|
case '@': |
||||
|
case '$': |
||||
|
size += 2; |
||||
|
break; |
||||
|
default: |
||||
|
if (*dn <= 0x20 || *dn >= 0x7f) |
||||
|
/* \ddd decimal notation */ |
||||
|
size += 4; |
||||
|
else |
||||
|
size += 1; |
||||
|
} |
||||
|
} while(++dn < le); |
||||
|
} |
||||
|
size += 1; /* zero byte at the end - string terminator */ |
||||
|
return size > DNS_MAXNAME ? 0 : size; |
||||
|
} |
||||
|
|
||||
|
/* Convert the dn into asciiz string.
|
||||
|
* Keep in sync with dns_dntop_size() above. |
||||
|
*/ |
||||
|
int dns_dntop(dnscc_t *dn, char *name, unsigned namesiz) { |
||||
|
char *np = name; /* current name ptr */ |
||||
|
char *const ne = name + namesiz; /* end of name */ |
||||
|
dnscc_t *le; /* label end */ |
||||
|
|
||||
|
while(*dn) { |
||||
|
/* *dn is the length of the next label, non-zero */ |
||||
|
if (np != name) { |
||||
|
if (np >= ne) goto toolong; |
||||
|
*np++ = '.'; |
||||
|
} |
||||
|
le = dn + *dn + 1; |
||||
|
++dn; |
||||
|
do { |
||||
|
switch(*dn) { |
||||
|
case '.': |
||||
|
case '\\': |
||||
|
/* Special modifiers in zone files. */ |
||||
|
case '"': |
||||
|
case ';': |
||||
|
case '@': |
||||
|
case '$': |
||||
|
if (np + 2 > ne) goto toolong; |
||||
|
*np++ = '\\'; |
||||
|
*np++ = *dn; |
||||
|
break; |
||||
|
default: |
||||
|
if (*dn <= 0x20 || *dn >= 0x7f) { |
||||
|
/* \ddd decimal notation */ |
||||
|
if (np + 4 >= ne) goto toolong; |
||||
|
*np++ = '\\'; |
||||
|
*np++ = '0' + (*dn / 100); |
||||
|
*np++ = '0' + ((*dn % 100) / 10); |
||||
|
*np++ = '0' + (*dn % 10); |
||||
|
} |
||||
|
else { |
||||
|
if (np >= ne) goto toolong; |
||||
|
*np++ = *dn; |
||||
|
} |
||||
|
} |
||||
|
} while(++dn < le); |
||||
|
} |
||||
|
if (np >= ne) goto toolong; |
||||
|
*np++ = '\0'; |
||||
|
return np - name; |
||||
|
toolong: |
||||
|
return namesiz >= DNS_MAXNAME ? -1 : 0; |
||||
|
} |
||||
|
|
||||
|
#ifdef TEST |
||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
|
||||
|
int main(int argc, char **argv) { |
||||
|
int i; |
||||
|
int sz; |
||||
|
dnsc_t dn[DNS_MAXDN+10]; |
||||
|
dnsc_t *dl, *dp; |
||||
|
int isabs; |
||||
|
|
||||
|
sz = (argc > 1) ? atoi(argv[1]) : 0; |
||||
|
|
||||
|
for(i = 2; i < argc; ++i) { |
||||
|
int r = dns_ptodn(argv[i], 0, dn, sz, &isabs); |
||||
|
printf("%s: ", argv[i]); |
||||
|
if (r < 0) printf("error\n"); |
||||
|
else if (!r) printf("buffer too small\n"); |
||||
|
else { |
||||
|
printf("len=%d dnlen=%d size=%d name:", |
||||
|
r, dns_dnlen(dn), dns_dntop_size(dn)); |
||||
|
dl = dn; |
||||
|
while(*dl) { |
||||
|
printf(" %d=", *dl); |
||||
|
dp = dl + 1; |
||||
|
dl = dp + *dl; |
||||
|
while(dp < dl) { |
||||
|
if (*dp <= ' ' || *dp >= 0x7f) |
||||
|
printf("\\%03d", *dp); |
||||
|
else if (*dp == '.' || *dp == '\\') |
||||
|
printf("\\%c", *dp); |
||||
|
else |
||||
|
putchar(*dp); |
||||
|
++dp; |
||||
|
} |
||||
|
} |
||||
|
if (isabs) putchar('.'); |
||||
|
putchar('\n'); |
||||
|
} |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
#endif /* TEST */ |
@ -0,0 +1,30 @@ |
|||||
|
/* $Id: udns_dntosp.c,v 1.5 2005/04/19 21:48:09 mjt Exp $
|
||||
|
dns_dntosp() = convert DN to asciiz string using static buffer |
||||
|
|
||||
|
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru> |
||||
|
This file is part of UDNS library, an async DNS stub resolver. |
||||
|
|
||||
|
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.1 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, in file named COPYING.LGPL; if not, |
||||
|
write to the Free Software Foundation, Inc., 59 Temple Place, |
||||
|
Suite 330, Boston, MA 02111-1307 USA |
||||
|
|
||||
|
*/ |
||||
|
|
||||
|
#include "udns.h" |
||||
|
|
||||
|
static char name[DNS_MAXNAME]; |
||||
|
|
||||
|
const char *dns_dntosp(dnscc_t *dn) { |
||||
|
return dns_dntop(dn, name, sizeof(name)) > 0 ? name : 0; |
||||
|
} |
@ -0,0 +1,231 @@ |
|||||
|
/* $Id: udns_init.c,v 1.6 2007/01/08 00:41:38 mjt Exp $
|
||||
|
resolver initialisation stuff |
||||
|
|
||||
|
Copyright (C) 2006 Michael Tokarev <mjt@corpit.ru> |
||||
|
This file is part of UDNS library, an async DNS stub resolver. |
||||
|
|
||||
|
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.1 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, in file named COPYING.LGPL; if not, |
||||
|
write to the Free Software Foundation, Inc., 59 Temple Place, |
||||
|
Suite 330, Boston, MA 02111-1307 USA |
||||
|
|
||||
|
*/ |
||||
|
|
||||
|
#ifdef HAVE_CONFIG_H |
||||
|
# include "config.h" |
||||
|
#endif |
||||
|
#ifdef WINDOWS |
||||
|
# include <winsock2.h> /* includes <windows.h> */ |
||||
|
# include <iphlpapi.h> /* for dns server addresses etc */ |
||||
|
#else |
||||
|
# include <sys/types.h> |
||||
|
# include <unistd.h> |
||||
|
# include <fcntl.h> |
||||
|
#endif /* !WINDOWS */ |
||||
|
|
||||
|
#include <stdlib.h> |
||||
|
#include <string.h> |
||||
|
#include "udns.h" |
||||
|
|
||||
|
#define ISSPACE(x) (x == ' ' || x == '\t' || x == '\r' || x == '\n') |
||||
|
|
||||
|
static const char space[] = " \t\r\n"; |
||||
|
|
||||
|
static void dns_set_serv_internal(struct dns_ctx *ctx, char *serv) { |
||||
|
dns_add_serv(ctx, NULL); |
||||
|
for(serv = strtok(serv, space); serv; serv = strtok(NULL, space)) |
||||
|
dns_add_serv(ctx, serv); |
||||
|
} |
||||
|
|
||||
|
static void dns_set_srch_internal(struct dns_ctx *ctx, char *srch) { |
||||
|
dns_add_srch(ctx, NULL); |
||||
|
for(srch = strtok(srch, space); srch; srch = strtok(NULL, space)) |
||||
|
dns_add_srch(ctx, srch); |
||||
|
} |
||||
|
|
||||
|
#ifdef WINDOWS |
||||
|
|
||||
|
#ifndef NO_IPHLPAPI |
||||
|
/* Apparently, some systems does not have proper headers for IPHLPAIP to work.
|
||||
|
* The best is to upgrade headers, but here's another, ugly workaround for |
||||
|
* this: compile with -DNO_IPHLPAPI. |
||||
|
*/ |
||||
|
|
||||
|
typedef DWORD (WINAPI *GetAdaptersAddressesFunc)( |
||||
|
ULONG Family, DWORD Flags, PVOID Reserved, |
||||
|
PIP_ADAPTER_ADDRESSES pAdapterAddresses, |
||||
|
PULONG pOutBufLen); |
||||
|
|
||||
|
static int dns_initns_iphlpapi(struct dns_ctx *ctx) { |
||||
|
HANDLE h_iphlpapi; |
||||
|
GetAdaptersAddressesFunc pfnGetAdAddrs; |
||||
|
PIP_ADAPTER_ADDRESSES pAddr, pAddrBuf; |
||||
|
PIP_ADAPTER_DNS_SERVER_ADDRESS pDnsAddr; |
||||
|
ULONG ulOutBufLen; |
||||
|
DWORD dwRetVal; |
||||
|
int ret = -1; |
||||
|
|
||||
|
h_iphlpapi = LoadLibrary("iphlpapi.dll"); |
||||
|
if (!h_iphlpapi) |
||||
|
return -1; |
||||
|
pfnGetAdAddrs = (GetAdaptersAddressesFunc) |
||||
|
GetProcAddress(h_iphlpapi, "GetAdaptersAddresses"); |
||||
|
if (!pfnGetAdAddrs) goto freelib; |
||||
|
ulOutBufLen = 0; |
||||
|
dwRetVal = pfnGetAdAddrs(AF_UNSPEC, 0, NULL, NULL, &ulOutBufLen); |
||||
|
if (dwRetVal != ERROR_BUFFER_OVERFLOW) goto freelib; |
||||
|
pAddrBuf = malloc(ulOutBufLen); |
||||
|
if (!pAddrBuf) goto freelib; |
||||
|
dwRetVal = pfnGetAdAddrs(AF_UNSPEC, 0, NULL, pAddrBuf, &ulOutBufLen); |
||||
|
if (dwRetVal != ERROR_SUCCESS) goto freemem; |
||||
|
for (pAddr = pAddrBuf; pAddr; pAddr = pAddr->Next) |
||||
|
for (pDnsAddr = pAddr->FirstDnsServerAddress; |
||||
|
pDnsAddr; |
||||
|
pDnsAddr = pDnsAddr->Next) |
||||
|
dns_add_serv_s(ctx, pDnsAddr->Address.lpSockaddr); |
||||
|
ret = 0; |
||||
|
freemem: |
||||
|
free(pAddrBuf); |
||||
|
freelib: |
||||
|
FreeLibrary(h_iphlpapi); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
#else /* NO_IPHLPAPI */ |
||||
|
|
||||
|
#define dns_initns_iphlpapi(ctx) (-1) |
||||
|
|
||||
|
#endif /* NO_IPHLPAPI */ |
||||
|
|
||||
|
static int dns_initns_registry(struct dns_ctx *ctx) { |
||||
|
LONG res; |
||||
|
HKEY hk; |
||||
|
DWORD type = REG_EXPAND_SZ | REG_SZ; |
||||
|
DWORD len; |
||||
|
char valBuf[1024]; |
||||
|
|
||||
|
#define REGKEY_WINNT "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters" |
||||
|
#define REGKEY_WIN9x "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP" |
||||
|
res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WINNT, 0, KEY_QUERY_VALUE, &hk); |
||||
|
if (res != ERROR_SUCCESS) |
||||
|
res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WIN9x, |
||||
|
0, KEY_QUERY_VALUE, &hk); |
||||
|
if (res != ERROR_SUCCESS) |
||||
|
return -1; |
||||
|
len = sizeof(valBuf) - 1; |
||||
|
res = RegQueryValueEx(hk, "NameServer", NULL, &type, (BYTE*)valBuf, &len); |
||||
|
if (res != ERROR_SUCCESS || !len || !valBuf[0]) { |
||||
|
len = sizeof(valBuf) - 1; |
||||
|
res = RegQueryValueEx(hk, "DhcpNameServer", NULL, &type, |
||||
|
(BYTE*)valBuf, &len); |
||||
|
} |
||||
|
RegCloseKey(hk); |
||||
|
if (res != ERROR_SUCCESS || !len || !valBuf[0]) |
||||
|
return -1; |
||||
|
valBuf[len] = '\0'; |
||||
|
/* nameservers are stored as a whitespace-seperate list:
|
||||
|
* "192.168.1.1 123.21.32.12" */ |
||||
|
dns_set_serv_internal(ctx, valBuf); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
#else /* !WINDOWS */ |
||||
|
|
||||
|
static int dns_init_resolvconf(struct dns_ctx *ctx) { |
||||
|
char *v; |
||||
|
char buf[2049]; /* this buffer is used to hold /etc/resolv.conf */ |
||||
|
int has_srch = 0; |
||||
|
|
||||
|
/* read resolv.conf... */ |
||||
|
{ int fd = open("/etc/resolv.conf", O_RDONLY); |
||||
|
if (fd >= 0) { |
||||
|
int l = read(fd, buf, sizeof(buf) - 1); |
||||
|
close(fd); |
||||
|
buf[l < 0 ? 0 : l] = '\0'; |
||||
|
} |
||||
|
else |
||||
|
buf[0] = '\0'; |
||||
|
} |
||||
|
if (buf[0]) { /* ...and parse it */ |
||||
|
char *line, *nextline; |
||||
|
line = buf; |
||||
|
do { |
||||
|
nextline = strchr(line, '\n'); |
||||
|
if (nextline) *nextline++ = '\0'; |
||||
|
v = line; |
||||
|
while(*v && !ISSPACE(*v)) ++v; |
||||
|
if (!*v) continue; |
||||
|
*v++ = '\0'; |
||||
|
while(ISSPACE(*v)) ++v; |
||||
|
if (!*v) continue; |
||||
|
if (strcmp(line, "domain") == 0) { |
||||
|
dns_set_srch_internal(ctx, strtok(v, space)); |
||||
|
has_srch = 1; |
||||
|
} |
||||
|
else if (strcmp(line, "search") == 0) { |
||||
|
dns_set_srch_internal(ctx, v); |
||||
|
has_srch = 1; |
||||
|
} |
||||
|
else if (strcmp(line, "nameserver") == 0) |
||||
|
dns_add_serv(ctx, strtok(v, space)); |
||||
|
else if (strcmp(line, "options") == 0) |
||||
|
dns_set_opts(ctx, v); |
||||
|
} while((line = nextline) != NULL); |
||||
|
} |
||||
|
|
||||
|
buf[sizeof(buf)-1] = '\0'; |
||||
|
|
||||
|
/* get list of nameservers from env. vars. */ |
||||
|
if ((v = getenv("NSCACHEIP")) != NULL || |
||||
|
(v = getenv("NAMESERVERS")) != NULL) { |
||||
|
strncpy(buf, v, sizeof(buf) - 1); |
||||
|
dns_set_serv_internal(ctx, buf); |
||||
|
} |
||||
|
/* if $LOCALDOMAIN is set, use it for search list */ |
||||
|
if ((v = getenv("LOCALDOMAIN")) != NULL) { |
||||
|
strncpy(buf, v, sizeof(buf) - 1); |
||||
|
dns_set_srch_internal(ctx, buf); |
||||
|
has_srch = 1; |
||||
|
} |
||||
|
if ((v = getenv("RES_OPTIONS")) != NULL) |
||||
|
dns_set_opts(ctx, v); |
||||
|
|
||||
|
/* if still no search list, use local domain name */ |
||||
|
if (has_srch && |
||||
|
gethostname(buf, sizeof(buf) - 1) == 0 && |
||||
|
(v = strchr(buf, '.')) != NULL && |
||||
|
*++v != '\0') |
||||
|
dns_add_srch(ctx, v); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
#endif /* !WINDOWS */ |
||||
|
|
||||
|
int dns_init(struct dns_ctx *ctx, int do_open) { |
||||
|
if (!ctx) |
||||
|
ctx = &dns_defctx; |
||||
|
dns_reset(ctx); |
||||
|
|
||||
|
#ifdef WINDOWS |
||||
|
if (dns_initns_iphlpapi(ctx) != 0) |
||||
|
dns_initns_registry(ctx); |
||||
|
/*XXX WINDOWS: probably good to get default domain and search list too...
|
||||
|
* And options. Something is in registry. */ |
||||
|
/*XXX WINDOWS: maybe environment variables are also useful? */ |
||||
|
#else |
||||
|
dns_init_resolvconf(ctx); |
||||
|
#endif |
||||
|
|
||||
|
return do_open ? dns_open(ctx) : 0; |
||||
|
} |
@ -0,0 +1,67 @@ |
|||||
|
/* $Id: udns_misc.c,v 1.8 2005/04/05 22:51:32 mjt Exp $
|
||||
|
miscellaneous routines |
||||
|
|
||||
|
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru> |
||||
|
This file is part of UDNS library, an async DNS stub resolver. |
||||
|
|
||||
|
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.1 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, in file named COPYING.LGPL; if not, |
||||
|
write to the Free Software Foundation, Inc., 59 Temple Place, |
||||
|
Suite 330, Boston, MA 02111-1307 USA |
||||
|
|
||||
|
*/ |
||||
|
|
||||
|
#include "udns.h" |
||||
|
|
||||
|
int dns_findname(const struct dns_nameval *nv, const char *name) { |
||||
|
register const char *a, *b; |
||||
|
for(; nv->name; ++nv) |
||||
|
for(a = name, b = nv->name; ; ++a, ++b) |
||||
|
if (DNS_DNUC(*a) != *b) break; |
||||
|
else if (!*a) return nv->val; |
||||
|
return -1; |
||||
|
} |
||||
|
|
||||
|
const char *_dns_format_code(char *buf, const char *prefix, int code) { |
||||
|
char *bp = buf; |
||||
|
unsigned c, n; |
||||
|
do *bp++ = DNS_DNUC(*prefix); |
||||
|
while(*++prefix); |
||||
|
*bp++ = '#'; |
||||
|
if (code < 0) code = -code, *bp++ = '-'; |
||||
|
n = 0; c = code; |
||||
|
do ++n; |
||||
|
while((c /= 10)); |
||||
|
c = code; |
||||
|
bp[n--] = '\0'; |
||||
|
do bp[n--] = c % 10 + '0'; |
||||
|
while((c /= 10)); |
||||
|
return buf; |
||||
|
} |
||||
|
|
||||
|
const char *dns_strerror(int err) { |
||||
|
if (err >= 0) return "successeful completion"; |
||||
|
switch(err) { |
||||
|
case DNS_E_TEMPFAIL: return "temporary failure in name resolution"; |
||||
|
case DNS_E_PROTOCOL: return "protocol error"; |
||||
|
case DNS_E_NXDOMAIN: return "domain name does not exist"; |
||||
|
case DNS_E_NODATA: return "valid domain but no data of requested type"; |
||||
|
case DNS_E_NOMEM: return "out of memory"; |
||||
|
case DNS_E_BADQUERY: return "malformed query"; |
||||
|
default: return "unknown error"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const char *dns_version(void) { |
||||
|
return UDNS_VERSION; |
||||
|
} |
@ -0,0 +1,169 @@ |
|||||
|
/* $Id: udns_parse.c,v 1.14 2005/09/12 10:55:21 mjt Exp $
|
||||
|
raw DNS packet parsing routines |
||||
|
|
||||
|
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru> |
||||
|
This file is part of UDNS library, an async DNS stub resolver. |
||||
|
|
||||
|
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.1 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, in file named COPYING.LGPL; if not, |
||||
|
write to the Free Software Foundation, Inc., 59 Temple Place, |
||||
|
Suite 330, Boston, MA 02111-1307 USA |
||||
|
|
||||
|
*/ |
||||
|
|
||||
|
#include <string.h> |
||||
|
#include <assert.h> |
||||
|
#include "udns.h" |
||||
|
|
||||
|
dnscc_t *dns_skipdn(dnscc_t *cur, dnscc_t *end) { |
||||
|
unsigned c; |
||||
|
for(;;) { |
||||
|
if (cur >= end) |
||||
|
return NULL; |
||||
|
c = *cur++; |
||||
|
if (!c) |
||||
|
return cur; |
||||
|
if (c & 192) /* jump */ |
||||
|
return cur + 1 >= end ? NULL : cur + 1; |
||||
|
cur += c; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
dns_getdn(dnscc_t *pkt, dnscc_t **cur, dnscc_t *end, |
||||
|
register dnsc_t *dn, unsigned dnsiz) { |
||||
|
unsigned c; |
||||
|
dnscc_t *pp = *cur; /* current packet pointer */ |
||||
|
dnsc_t *dp = dn; /* current dn pointer */ |
||||
|
dnsc_t *const de /* end of the DN dest */ |
||||
|
= dn + (dnsiz < DNS_MAXDN ? dnsiz : DNS_MAXDN); |
||||
|
dnscc_t *jump = NULL; /* ptr after first jump if any */ |
||||
|
unsigned loop = 100; /* jump loop counter */ |
||||
|
|
||||
|
for(;;) { /* loop by labels */ |
||||
|
if (pp >= end) /* reached end of packet? */ |
||||
|
return -1; |
||||
|
c = *pp++; /* length of the label */ |
||||
|
if (!c) { /* empty label: terminate */ |
||||
|
if (dn >= de) /* can't fit terminator */ |
||||
|
goto noroom; |
||||
|
*dp++ = 0; |
||||
|
/* return next pos: either after the first jump or current */ |
||||
|
*cur = jump ? jump : pp; |
||||
|
return dp - dn; |
||||
|
} |
||||
|
if (c & 192) { /* jump */ |
||||
|
if (pp >= end) /* eop instead of jump pos */ |
||||
|
return -1; |
||||
|
if (!jump) jump = pp + 1; /* remember first jump */ |
||||
|
else if (!--loop) return -1; /* too many jumps */ |
||||
|
c = ((c & ~192) << 8) | *pp; /* new pos */ |
||||
|
if (c < DNS_HSIZE) /* don't allow jump into the header */ |
||||
|
return -1; |
||||
|
pp = pkt + c; |
||||
|
continue; |
||||
|
} |
||||
|
if (c > DNS_MAXLABEL) /* too long label? */ |
||||
|
return -1; |
||||
|
if (pp + c > end) /* label does not fit in packet? */ |
||||
|
return -1; |
||||
|
if (dp + c + 1 > de) /* if enouth room for the label */ |
||||
|
goto noroom; |
||||
|
*dp++ = c; /* label length */ |
||||
|
memcpy(dp, pp, c); /* and the label itself */ |
||||
|
dp += c; |
||||
|
pp += c; /* advance to the next label */ |
||||
|
} |
||||
|
noroom: |
||||
|
return dnsiz < DNS_MAXDN ? 0 : -1; |
||||
|
} |
||||
|
|
||||
|
void dns_rewind(struct dns_parse *p, dnscc_t *qdn) { |
||||
|
p->dnsp_qdn = qdn; |
||||
|
p->dnsp_cur = p->dnsp_ans; |
||||
|
p->dnsp_rrl = dns_numan(p->dnsp_pkt); |
||||
|
p->dnsp_ttl = 0xffffffffu; |
||||
|
p->dnsp_nrr = 0; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
dns_initparse(struct dns_parse *p, dnscc_t *qdn, |
||||
|
dnscc_t *pkt, dnscc_t *cur, dnscc_t *end) { |
||||
|
p->dnsp_pkt = pkt; |
||||
|
p->dnsp_end = end; |
||||
|
p->dnsp_rrl = dns_numan(pkt); |
||||
|
p->dnsp_qdn = qdn; |
||||
|
assert(cur + 4 <= end); |
||||
|
if ((p->dnsp_qtyp = dns_get16(cur+0)) == DNS_T_ANY) p->dnsp_qtyp = 0; |
||||
|
if ((p->dnsp_qcls = dns_get16(cur+2)) == DNS_C_ANY) p->dnsp_qcls = 0; |
||||
|
p->dnsp_cur = p->dnsp_ans = cur + 4; |
||||
|
p->dnsp_ttl = 0xffffffffu; |
||||
|
p->dnsp_nrr = 0; |
||||
|
} |
||||
|
|
||||
|
int dns_nextrr(struct dns_parse *p, struct dns_rr *rr) { |
||||
|
dnscc_t *cur = p->dnsp_cur; |
||||
|
while(p->dnsp_rrl > 0) { |
||||
|
--p->dnsp_rrl; |
||||
|
if (dns_getdn(p->dnsp_pkt, &cur, p->dnsp_end, |
||||
|
rr->dnsrr_dn, sizeof(rr->dnsrr_dn)) <= 0) |
||||
|
return -1; |
||||
|
if (cur + 10 > p->dnsp_end) |
||||
|
return -1; |
||||
|
rr->dnsrr_typ = dns_get16(cur); |
||||
|
rr->dnsrr_cls = dns_get16(cur+2); |
||||
|
rr->dnsrr_ttl = dns_get32(cur+4); |
||||
|
rr->dnsrr_dsz = dns_get16(cur+8); |
||||
|
rr->dnsrr_dptr = cur = cur + 10; |
||||
|
rr->dnsrr_dend = cur = cur + rr->dnsrr_dsz; |
||||
|
if (cur > p->dnsp_end) |
||||
|
return -1; |
||||
|
if (p->dnsp_qdn && !dns_dnequal(p->dnsp_qdn, rr->dnsrr_dn)) |
||||
|
continue; |
||||
|
if ((!p->dnsp_qcls || p->dnsp_qcls == rr->dnsrr_cls) && |
||||
|
(!p->dnsp_qtyp || p->dnsp_qtyp == rr->dnsrr_typ)) { |
||||
|
p->dnsp_cur = cur; |
||||
|
++p->dnsp_nrr; |
||||
|
if (p->dnsp_ttl > rr->dnsrr_ttl) p->dnsp_ttl = rr->dnsrr_ttl; |
||||
|
return 1; |
||||
|
} |
||||
|
if (p->dnsp_qdn && rr->dnsrr_typ == DNS_T_CNAME && !p->dnsp_nrr) { |
||||
|
if (dns_getdn(p->dnsp_pkt, &rr->dnsrr_dptr, p->dnsp_end, |
||||
|
p->dnsp_dnbuf, sizeof(p->dnsp_dnbuf)) <= 0 || |
||||
|
rr->dnsrr_dptr != rr->dnsrr_dend) |
||||
|
return -1; |
||||
|
p->dnsp_qdn = p->dnsp_dnbuf; |
||||
|
if (p->dnsp_ttl > rr->dnsrr_ttl) p->dnsp_ttl = rr->dnsrr_ttl; |
||||
|
} |
||||
|
} |
||||
|
p->dnsp_cur = cur; |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int dns_stdrr_size(const struct dns_parse *p) { |
||||
|
return |
||||
|
dns_dntop_size(p->dnsp_qdn) + |
||||
|
(p->dnsp_qdn == dns_payload(p->dnsp_pkt) ? 0 : |
||||
|
dns_dntop_size(dns_payload(p->dnsp_pkt))); |
||||
|
} |
||||
|
|
||||
|
void *dns_stdrr_finish(struct dns_rr_null *ret, char *cp, |
||||
|
const struct dns_parse *p) { |
||||
|
cp += dns_dntop(p->dnsp_qdn, (ret->dnsn_cname = cp), DNS_MAXNAME); |
||||
|
if (p->dnsp_qdn == dns_payload(p->dnsp_pkt)) |
||||
|
ret->dnsn_qname = ret->dnsn_cname; |
||||
|
else |
||||
|
dns_dntop(dns_payload(p->dnsp_pkt), (ret->dnsn_qname = cp), DNS_MAXNAME); |
||||
|
ret->dnsn_ttl = p->dnsp_ttl; |
||||
|
return ret; |
||||
|
} |
File diff suppressed because it is too large
@ -0,0 +1,123 @@ |
|||||
|
/* $Id: udns_rr_a.c,v 1.16 2007/01/09 04:44:51 mjt Exp $
|
||||
|
parse/query A/AAAA IN records |
||||
|
|
||||
|
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru> |
||||
|
This file is part of UDNS library, an async DNS stub resolver. |
||||
|
|
||||
|
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.1 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, in file named COPYING.LGPL; if not, |
||||
|
write to the Free Software Foundation, Inc., 59 Temple Place, |
||||
|
Suite 330, Boston, MA 02111-1307 USA |
||||
|
|
||||
|
*/ |
||||
|
|
||||
|
#include <string.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <assert.h> |
||||
|
#ifndef WINDOWS |
||||
|
# include <sys/types.h> |
||||
|
# include <netinet/in.h> |
||||
|
#endif |
||||
|
#include "udns.h" |
||||
|
|
||||
|
/* here, we use common routine to parse both IPv4 and IPv6 addresses.
|
||||
|
*/ |
||||
|
|
||||
|
/* this structure should match dns_rr_a[46] */ |
||||
|
struct dns_rr_a { |
||||
|
dns_rr_common(dnsa); |
||||
|
unsigned char *dnsa_addr; |
||||
|
}; |
||||
|
|
||||
|
static int |
||||
|
dns_parse_a(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end, |
||||
|
void **result, unsigned dsize) { |
||||
|
struct dns_rr_a *ret; |
||||
|
struct dns_parse p; |
||||
|
struct dns_rr rr; |
||||
|
int r; |
||||
|
|
||||
|
/* first, validate and count number of addresses */ |
||||
|
dns_initparse(&p, qdn, pkt, cur, end); |
||||
|
while((r = dns_nextrr(&p, &rr)) > 0) |
||||
|
if (rr.dnsrr_dsz != dsize) |
||||
|
return DNS_E_PROTOCOL; |
||||
|
if (r < 0) |
||||
|
return DNS_E_PROTOCOL; |
||||
|
else if (!p.dnsp_nrr) |
||||
|
return DNS_E_NODATA; |
||||
|
|
||||
|
ret = malloc(sizeof(*ret) + dsize * p.dnsp_nrr + dns_stdrr_size(&p)); |
||||
|
if (!ret) |
||||
|
return DNS_E_NOMEM; |
||||
|
|
||||
|
ret->dnsa_nrr = p.dnsp_nrr; |
||||
|
ret->dnsa_addr = (unsigned char*)(ret+1); |
||||
|
|
||||
|
/* copy the RRs */ |
||||
|
for (dns_rewind(&p, qdn), r = 0; dns_nextrr(&p, &rr); ++r) |
||||
|
memcpy(ret->dnsa_addr + dsize * r, rr.dnsrr_dptr, dsize); |
||||
|
|
||||
|
dns_stdrr_finish((struct dns_rr_null *)ret, |
||||
|
(char *)(ret->dnsa_addr + dsize * p.dnsp_nrr), &p); |
||||
|
*result = ret; |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
dns_parse_a4(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end, |
||||
|
void **result) { |
||||
|
#ifdef AF_INET |
||||
|
assert(sizeof(struct in_addr) == 4); |
||||
|
#endif |
||||
|
assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_A); |
||||
|
return dns_parse_a(qdn, pkt, cur, end, result, 4); |
||||
|
} |
||||
|
|
||||
|
struct dns_query * |
||||
|
dns_submit_a4(struct dns_ctx *ctx, const char *name, int flags, |
||||
|
dns_query_a4_fn *cbck, void *data) { |
||||
|
return |
||||
|
dns_submit_p(ctx, name, DNS_C_IN, DNS_T_A, flags, |
||||
|
dns_parse_a4, (dns_query_fn*)cbck, data); |
||||
|
} |
||||
|
|
||||
|
struct dns_rr_a4 * |
||||
|
dns_resolve_a4(struct dns_ctx *ctx, const char *name, int flags) { |
||||
|
return (struct dns_rr_a4 *) |
||||
|
dns_resolve_p(ctx, name, DNS_C_IN, DNS_T_A, flags, dns_parse_a4); |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
dns_parse_a6(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end, |
||||
|
void **result) { |
||||
|
#ifdef AF_INET6 |
||||
|
assert(sizeof(struct in6_addr) == 16); |
||||
|
#endif |
||||
|
assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_AAAA); |
||||
|
return dns_parse_a(qdn, pkt, cur, end, result, 16); |
||||
|
} |
||||
|
|
||||
|
struct dns_query * |
||||
|
dns_submit_a6(struct dns_ctx *ctx, const char *name, int flags, |
||||
|
dns_query_a6_fn *cbck, void *data) { |
||||
|
return |
||||
|
dns_submit_p(ctx, name, DNS_C_IN, DNS_T_AAAA, flags, |
||||
|
dns_parse_a6, (dns_query_fn*)cbck, data); |
||||
|
} |
||||
|
|
||||
|
struct dns_rr_a6 * |
||||
|
dns_resolve_a6(struct dns_ctx *ctx, const char *name, int flags) { |
||||
|
return (struct dns_rr_a6 *) |
||||
|
dns_resolve_p(ctx, name, DNS_C_IN, DNS_T_AAAA, flags, dns_parse_a6); |
||||
|
} |
@ -0,0 +1,91 @@ |
|||||
|
/* $Id: udns_rr_mx.c,v 1.13 2005/04/20 06:44:34 mjt Exp $
|
||||
|
parse/query MX IN records |
||||
|
|
||||
|
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru> |
||||
|
This file is part of UDNS library, an async DNS stub resolver. |
||||
|
|
||||
|
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.1 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, in file named COPYING.LGPL; if not, |
||||
|
write to the Free Software Foundation, Inc., 59 Temple Place, |
||||
|
Suite 330, Boston, MA 02111-1307 USA |
||||
|
|
||||
|
*/ |
||||
|
|
||||
|
#include <string.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <assert.h> |
||||
|
#include "udns.h" |
||||
|
|
||||
|
int |
||||
|
dns_parse_mx(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end, |
||||
|
void **result) { |
||||
|
struct dns_rr_mx *ret; |
||||
|
struct dns_parse p; |
||||
|
struct dns_rr rr; |
||||
|
int r, l; |
||||
|
char *sp; |
||||
|
dnsc_t mx[DNS_MAXDN]; |
||||
|
|
||||
|
assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_MX); |
||||
|
|
||||
|
/* first, validate the answer and count size of the result */ |
||||
|
l = 0; |
||||
|
dns_initparse(&p, qdn, pkt, cur, end); |
||||
|
while((r = dns_nextrr(&p, &rr)) > 0) { |
||||
|
cur = rr.dnsrr_dptr + 2; |
||||
|
r = dns_getdn(pkt, &cur, end, mx, sizeof(mx)); |
||||
|
if (r <= 0 || cur != rr.dnsrr_dend) |
||||
|
return DNS_E_PROTOCOL; |
||||
|
l += dns_dntop_size(mx); |
||||
|
} |
||||
|
if (r < 0) |
||||
|
return DNS_E_PROTOCOL; |
||||
|
if (!p.dnsp_nrr) |
||||
|
return DNS_E_NODATA; |
||||
|
|
||||
|
/* next, allocate and set up result */ |
||||
|
l += dns_stdrr_size(&p); |
||||
|
ret = malloc(sizeof(*ret) + sizeof(struct dns_mx) * p.dnsp_nrr + l); |
||||
|
if (!ret) |
||||
|
return DNS_E_NOMEM; |
||||
|
ret->dnsmx_nrr = p.dnsp_nrr; |
||||
|
ret->dnsmx_mx = (struct dns_mx *)(ret+1); |
||||
|
|
||||
|
/* and 3rd, fill in result, finally */ |
||||
|
sp = (char*)(ret->dnsmx_mx + p.dnsp_nrr); |
||||
|
for (dns_rewind(&p, qdn), r = 0; dns_nextrr(&p, &rr); ++r) { |
||||
|
ret->dnsmx_mx[r].name = sp; |
||||
|
cur = rr.dnsrr_dptr; |
||||
|
ret->dnsmx_mx[r].priority = dns_get16(cur); |
||||
|
cur += 2; |
||||
|
dns_getdn(pkt, &cur, end, mx, sizeof(mx)); |
||||
|
sp += dns_dntop(mx, sp, DNS_MAXNAME); |
||||
|
} |
||||
|
dns_stdrr_finish((struct dns_rr_null *)ret, sp, &p); |
||||
|
*result = ret; |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
struct dns_query * |
||||
|
dns_submit_mx(struct dns_ctx *ctx, const char *name, int flags, |
||||
|
dns_query_mx_fn *cbck, void *data) { |
||||
|
return |
||||
|
dns_submit_p(ctx, name, DNS_C_IN, DNS_T_MX, flags, |
||||
|
dns_parse_mx, (dns_query_fn *)cbck, data); |
||||
|
} |
||||
|
|
||||
|
struct dns_rr_mx * |
||||
|
dns_resolve_mx(struct dns_ctx *ctx, const char *name, int flags) { |
||||
|
return (struct dns_rr_mx *) |
||||
|
dns_resolve_p(ctx, name, DNS_C_IN, DNS_T_MX, flags, dns_parse_mx); |
||||
|
} |
@ -0,0 +1,128 @@ |
|||||
|
/* $Id: udns_rr_naptr.c,v 1.1 2006/11/28 22:58:04 mjt Exp $
|
||||
|
parse/query NAPTR IN records |
||||
|
|
||||
|
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru> |
||||
|
Copyright (C) 2006 Mikael Magnusson <mikma@users.sourceforge.net> |
||||
|
This file is part of UDNS library, an async DNS stub resolver. |
||||
|
|
||||
|
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.1 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, in file named COPYING.LGPL; if not, |
||||
|
write to the Free Software Foundation, Inc., 59 Temple Place, |
||||
|
Suite 330, Boston, MA 02111-1307 USA |
||||
|
|
||||
|
*/ |
||||
|
|
||||
|
#include <string.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <assert.h> |
||||
|
#include "udns.h" |
||||
|
|
||||
|
/* Get a single string for NAPTR record, pretty much like a DN label.
|
||||
|
* String length is in first byte in *cur, so it can't be >255. |
||||
|
*/ |
||||
|
static int dns_getstr(dnscc_t **cur, dnscc_t *ep, char *buf) |
||||
|
{ |
||||
|
unsigned l; |
||||
|
dnscc_t *cp = *cur; |
||||
|
|
||||
|
l = *cp++; |
||||
|
if (cp + l > ep) |
||||
|
return DNS_E_PROTOCOL; |
||||
|
if (buf) { |
||||
|
memcpy(buf, cp, l); |
||||
|
buf[l] = '\0'; |
||||
|
} |
||||
|
cp += l; |
||||
|
|
||||
|
*cur = cp; |
||||
|
return l + 1; |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
dns_parse_naptr(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end, |
||||
|
void **result) { |
||||
|
struct dns_rr_naptr *ret; |
||||
|
struct dns_parse p; |
||||
|
struct dns_rr rr; |
||||
|
int r, l; |
||||
|
char *sp; |
||||
|
dnsc_t dn[DNS_MAXDN]; |
||||
|
|
||||
|
assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_NAPTR); |
||||
|
|
||||
|
/* first, validate the answer and count size of the result */ |
||||
|
l = 0; |
||||
|
dns_initparse(&p, qdn, pkt, cur, end); |
||||
|
while((r = dns_nextrr(&p, &rr)) > 0) { |
||||
|
int i; |
||||
|
dnscc_t *ep = rr.dnsrr_dend; |
||||
|
|
||||
|
/* first 4 bytes: order & preference */ |
||||
|
cur = rr.dnsrr_dptr + 4; |
||||
|
|
||||
|
/* flags, services and regexp */ |
||||
|
for (i = 0; i < 3; i++) { |
||||
|
r = dns_getstr(&cur, ep, NULL); |
||||
|
if (r < 0) |
||||
|
return r; |
||||
|
l += r; |
||||
|
} |
||||
|
/* replacement */ |
||||
|
r = dns_getdn(pkt, &cur, end, dn, sizeof(dn)); |
||||
|
if (r <= 0 || cur != rr.dnsrr_dend) |
||||
|
return DNS_E_PROTOCOL; |
||||
|
l += dns_dntop_size(dn); |
||||
|
} |
||||
|
if (r < 0) |
||||
|
return DNS_E_PROTOCOL; |
||||
|
if (!p.dnsp_nrr) |
||||
|
return DNS_E_NODATA; |
||||
|
|
||||
|
/* next, allocate and set up result */ |
||||
|
l += dns_stdrr_size(&p); |
||||
|
ret = malloc(sizeof(*ret) + sizeof(struct dns_naptr) * p.dnsp_nrr + l); |
||||
|
if (!ret) |
||||
|
return DNS_E_NOMEM; |
||||
|
ret->dnsnaptr_nrr = p.dnsp_nrr; |
||||
|
ret->dnsnaptr_naptr = (struct dns_naptr *)(ret+1); |
||||
|
|
||||
|
/* and 3rd, fill in result, finally */ |
||||
|
sp = (char*)(&ret->dnsnaptr_naptr[p.dnsp_nrr]); |
||||
|
for (dns_rewind(&p, qdn), r = 0; dns_nextrr(&p, &rr); ++r) { |
||||
|
cur = rr.dnsrr_dptr; |
||||
|
ret->dnsnaptr_naptr[r].order = dns_get16(cur); cur += 2; |
||||
|
ret->dnsnaptr_naptr[r].preference = dns_get16(cur); cur += 2; |
||||
|
sp += dns_getstr(&cur, end, (ret->dnsnaptr_naptr[r].flags = sp)); |
||||
|
sp += dns_getstr(&cur, end, (ret->dnsnaptr_naptr[r].service = sp)); |
||||
|
sp += dns_getstr(&cur, end, (ret->dnsnaptr_naptr[r].regexp = sp)); |
||||
|
dns_getdn(pkt, &cur, end, dn, sizeof(dn)); |
||||
|
sp += dns_dntop(dn, (ret->dnsnaptr_naptr[r].replacement = sp), DNS_MAXNAME); |
||||
|
} |
||||
|
dns_stdrr_finish((struct dns_rr_null *)ret, sp, &p); |
||||
|
*result = ret; |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
struct dns_query * |
||||
|
dns_submit_naptr(struct dns_ctx *ctx, const char *name, int flags, |
||||
|
dns_query_naptr_fn *cbck, void *data) { |
||||
|
return |
||||
|
dns_submit_p(ctx, name, DNS_C_IN, DNS_T_NAPTR, flags, |
||||
|
dns_parse_naptr, (dns_query_fn *)cbck, data); |
||||
|
} |
||||
|
|
||||
|
struct dns_rr_naptr * |
||||
|
dns_resolve_naptr(struct dns_ctx *ctx, const char *name, int flags) { |
||||
|
return (struct dns_rr_naptr *) |
||||
|
dns_resolve_p(ctx, name, DNS_C_IN, DNS_T_NAPTR, flags, dns_parse_naptr); |
||||
|
} |
@ -0,0 +1,109 @@ |
|||||
|
/* $Id: udns_rr_ptr.c,v 1.15 2005/09/12 11:21:06 mjt Exp $
|
||||
|
parse/query PTR records |
||||
|
|
||||
|
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru> |
||||
|
This file is part of UDNS library, an async DNS stub resolver. |
||||
|
|
||||
|
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.1 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, in file named COPYING.LGPL; if not, |
||||
|
write to the Free Software Foundation, Inc., 59 Temple Place, |
||||
|
Suite 330, Boston, MA 02111-1307 USA |
||||
|
|
||||
|
*/ |
||||
|
|
||||
|
#include <stdlib.h> |
||||
|
#include <assert.h> |
||||
|
#include "udns.h" |
||||
|
|
||||
|
int |
||||
|
dns_parse_ptr(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end, |
||||
|
void **result) { |
||||
|
struct dns_rr_ptr *ret; |
||||
|
struct dns_parse p; |
||||
|
struct dns_rr rr; |
||||
|
int r, l, c; |
||||
|
char *sp; |
||||
|
dnsc_t ptr[DNS_MAXDN]; |
||||
|
|
||||
|
assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_PTR); |
||||
|
|
||||
|
/* first, validate the answer and count size of the result */ |
||||
|
l = c = 0; |
||||
|
dns_initparse(&p, qdn, pkt, cur, end); |
||||
|
while((r = dns_nextrr(&p, &rr)) > 0) { |
||||
|
cur = rr.dnsrr_dptr; |
||||
|
r = dns_getdn(pkt, &cur, end, ptr, sizeof(ptr)); |
||||
|
if (r <= 0 || cur != rr.dnsrr_dend) |
||||
|
return DNS_E_PROTOCOL; |
||||
|
l += dns_dntop_size(ptr); |
||||
|
++c; |
||||
|
} |
||||
|
if (r < 0) |
||||
|
return DNS_E_PROTOCOL; |
||||
|
if (!c) |
||||
|
return DNS_E_NODATA; |
||||
|
|
||||
|
/* next, allocate and set up result */ |
||||
|
ret = malloc(sizeof(*ret) + sizeof(char **) * c + l + dns_stdrr_size(&p)); |
||||
|
if (!ret) |
||||
|
return DNS_E_NOMEM; |
||||
|
ret->dnsptr_nrr = c; |
||||
|
ret->dnsptr_ptr = (char **)(ret+1); |
||||
|
|
||||
|
/* and 3rd, fill in result, finally */ |
||||
|
sp = (char*)(ret->dnsptr_ptr + c); |
||||
|
c = 0; |
||||
|
dns_rewind(&p, qdn); |
||||
|
while((r = dns_nextrr(&p, &rr)) > 0) { |
||||
|
ret->dnsptr_ptr[c] = sp; |
||||
|
cur = rr.dnsrr_dptr; |
||||
|
dns_getdn(pkt, &cur, end, ptr, sizeof(ptr)); |
||||
|
sp += dns_dntop(ptr, sp, DNS_MAXNAME); |
||||
|
++c; |
||||
|
} |
||||
|
dns_stdrr_finish((struct dns_rr_null *)ret, sp, &p); |
||||
|
*result = ret; |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
struct dns_query * |
||||
|
dns_submit_a4ptr(struct dns_ctx *ctx, const struct in_addr *addr, |
||||
|
dns_query_ptr_fn *cbck, void *data) { |
||||
|
dnsc_t dn[DNS_A4RSIZE]; |
||||
|
dns_a4todn(addr, 0, dn, sizeof(dn)); |
||||
|
return |
||||
|
dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_PTR, DNS_NOSRCH, |
||||
|
dns_parse_ptr, (dns_query_fn *)cbck, data); |
||||
|
} |
||||
|
|
||||
|
struct dns_rr_ptr * |
||||
|
dns_resolve_a4ptr(struct dns_ctx *ctx, const struct in_addr *addr) { |
||||
|
return (struct dns_rr_ptr *) |
||||
|
dns_resolve(ctx, dns_submit_a4ptr(ctx, addr, NULL, NULL)); |
||||
|
} |
||||
|
|
||||
|
struct dns_query * |
||||
|
dns_submit_a6ptr(struct dns_ctx *ctx, const struct in6_addr *addr, |
||||
|
dns_query_ptr_fn *cbck, void *data) { |
||||
|
dnsc_t dn[DNS_A6RSIZE]; |
||||
|
dns_a6todn(addr, 0, dn, sizeof(dn)); |
||||
|
return |
||||
|
dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_PTR, DNS_NOSRCH, |
||||
|
dns_parse_ptr, (dns_query_fn *)cbck, data); |
||||
|
} |
||||
|
|
||||
|
struct dns_rr_ptr * |
||||
|
dns_resolve_a6ptr(struct dns_ctx *ctx, const struct in6_addr *addr) { |
||||
|
return (struct dns_rr_ptr *) |
||||
|
dns_resolve(ctx, dns_submit_a6ptr(ctx, addr, NULL, NULL)); |
||||
|
} |
@ -0,0 +1,154 @@ |
|||||
|
/* $Id: udns_rr_srv.c,v 1.2 2005/09/12 12:26:22 mjt Exp $
|
||||
|
parse/query SRV IN (rfc2782) records |
||||
|
|
||||
|
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru> |
||||
|
This file is part of UDNS library, an async DNS stub resolver. |
||||
|
|
||||
|
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.1 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, in file named COPYING.LGPL; if not, |
||||
|
write to the Free Software Foundation, Inc., 59 Temple Place, |
||||
|
Suite 330, Boston, MA 02111-1307 USA |
||||
|
|
||||
|
Copyright 2005 Thadeu Lima de Souza Cascardo <cascardo@minaslivre.org> |
||||
|
|
||||
|
2005-09-11: |
||||
|
Changed MX parser file into a SRV parser file |
||||
|
|
||||
|
*/ |
||||
|
|
||||
|
#include <string.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <assert.h> |
||||
|
#include "udns.h" |
||||
|
|
||||
|
int |
||||
|
dns_parse_srv(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end, |
||||
|
void **result) { |
||||
|
struct dns_rr_srv *ret; |
||||
|
struct dns_parse p; |
||||
|
struct dns_rr rr; |
||||
|
int r, l; |
||||
|
char *sp; |
||||
|
dnsc_t srv[DNS_MAXDN]; |
||||
|
|
||||
|
assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_SRV); |
||||
|
|
||||
|
/* first, validate the answer and count size of the result */ |
||||
|
l = 0; |
||||
|
dns_initparse(&p, qdn, pkt, cur, end); |
||||
|
while((r = dns_nextrr(&p, &rr)) > 0) { |
||||
|
cur = rr.dnsrr_dptr + 6; |
||||
|
r = dns_getdn(pkt, &cur, end, srv, sizeof(srv)); |
||||
|
if (r <= 0 || cur != rr.dnsrr_dend) |
||||
|
return DNS_E_PROTOCOL; |
||||
|
l += dns_dntop_size(srv); |
||||
|
} |
||||
|
if (r < 0) |
||||
|
return DNS_E_PROTOCOL; |
||||
|
if (!p.dnsp_nrr) |
||||
|
return DNS_E_NODATA; |
||||
|
|
||||
|
/* next, allocate and set up result */ |
||||
|
l += dns_stdrr_size(&p); |
||||
|
ret = malloc(sizeof(*ret) + sizeof(struct dns_srv) * p.dnsp_nrr + l); |
||||
|
if (!ret) |
||||
|
return DNS_E_NOMEM; |
||||
|
ret->dnssrv_nrr = p.dnsp_nrr; |
||||
|
ret->dnssrv_srv = (struct dns_srv *)(ret+1); |
||||
|
|
||||
|
/* and 3rd, fill in result, finally */ |
||||
|
sp = (char*)(ret->dnssrv_srv + p.dnsp_nrr); |
||||
|
for (dns_rewind(&p, qdn), r = 0; dns_nextrr(&p, &rr); ++r) { |
||||
|
ret->dnssrv_srv[r].name = sp; |
||||
|
cur = rr.dnsrr_dptr; |
||||
|
ret->dnssrv_srv[r].priority = dns_get16(cur); |
||||
|
ret->dnssrv_srv[r].weight = dns_get16(cur+2); |
||||
|
ret->dnssrv_srv[r].port = dns_get16(cur+4); |
||||
|
cur += 6; |
||||
|
dns_getdn(pkt, &cur, end, srv, sizeof(srv)); |
||||
|
sp += dns_dntop(srv, sp, DNS_MAXNAME); |
||||
|
} |
||||
|
dns_stdrr_finish((struct dns_rr_null *)ret, sp, &p); |
||||
|
*result = ret; |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
/* Add a single service or proto name prepending an undescore (_),
|
||||
|
* according to rfc2782 rules. |
||||
|
* Return 0 or the label length. |
||||
|
* Routing assumes dn holds enouth space for a single DN label. */ |
||||
|
static unsigned add_sname(dnsc_t *dn, const char *sn) { |
||||
|
unsigned l; |
||||
|
l = dns_ptodn(sn, 0, dn + 1, DNS_MAXLABEL-1, NULL); |
||||
|
if (l <= 1 || l - 2 != dn[1]) |
||||
|
/* Should we really check if sn is exactly one label? Do we care? */ |
||||
|
return 0; |
||||
|
dn[0] = l - 1; |
||||
|
dn[1] = '_'; |
||||
|
return l; |
||||
|
} |
||||
|
|
||||
|
/* Construct a domain name for SRV query from the given name, service and
|
||||
|
* protocol (service may be NULL in which case protocol isn't used). |
||||
|
* Return negative value on error (malformed query), |
||||
|
* or addition query flag(s) to use. |
||||
|
*/ |
||||
|
static int |
||||
|
build_srv_dn(dnsc_t *dn, const char *name, const char *srv, const char *proto) |
||||
|
{ |
||||
|
unsigned p = 0, l; |
||||
|
int isabs; |
||||
|
if (srv) { |
||||
|
l = add_sname(dn + p, srv); |
||||
|
if (!l) |
||||
|
return -1; |
||||
|
p += l; |
||||
|
l = add_sname(dn + p, proto); |
||||
|
if (!l) |
||||
|
return -1; |
||||
|
p += l; |
||||
|
} |
||||
|
l = dns_ptodn(name, 0, dn + p, DNS_MAXDN - p, &isabs); |
||||
|
if (!l) |
||||
|
return -1; |
||||
|
return isabs ? DNS_NOSRCH : 0; |
||||
|
} |
||||
|
|
||||
|
struct dns_query * |
||||
|
dns_submit_srv(struct dns_ctx *ctx, |
||||
|
const char *name, const char *srv, const char *proto, |
||||
|
int flags, dns_query_srv_fn *cbck, void *data) { |
||||
|
dnsc_t dn[DNS_MAXDN]; |
||||
|
int r = build_srv_dn(dn, name, srv, proto); |
||||
|
if (r < 0) { |
||||
|
dns_setstatus (ctx, DNS_E_BADQUERY); |
||||
|
return NULL; |
||||
|
} |
||||
|
return |
||||
|
dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_SRV, flags | r, |
||||
|
dns_parse_srv, (dns_query_fn *)cbck, data); |
||||
|
} |
||||
|
|
||||
|
struct dns_rr_srv * |
||||
|
dns_resolve_srv(struct dns_ctx *ctx, |
||||
|
const char *name, const char *srv, const char *proto, int flags) |
||||
|
{ |
||||
|
dnsc_t dn[DNS_MAXDN]; |
||||
|
int r = build_srv_dn(dn, name, srv, proto); |
||||
|
if (r < 0) { |
||||
|
dns_setstatus(ctx, DNS_E_BADQUERY); |
||||
|
return NULL; |
||||
|
} |
||||
|
return (struct dns_rr_srv *) |
||||
|
dns_resolve_dn(ctx, dn, DNS_C_IN, DNS_T_SRV, flags | r, dns_parse_srv); |
||||
|
} |
@ -0,0 +1,98 @@ |
|||||
|
/* $Id: udns_rr_txt.c,v 1.15 2006/11/28 22:45:20 mjt Exp $
|
||||
|
parse/query TXT records |
||||
|
|
||||
|
Copyright (C) 2005 Michael Tokarev <mjt@corpit.ru> |
||||
|
This file is part of UDNS library, an async DNS stub resolver. |
||||
|
|
||||
|
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.1 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, in file named COPYING.LGPL; if not, |
||||
|
write to the Free Software Foundation, Inc., 59 Temple Place, |
||||
|
Suite 330, Boston, MA 02111-1307 USA |
||||
|
|
||||
|
*/ |
||||
|
|
||||
|
#include <string.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <assert.h> |
||||
|
#include "udns.h" |
||||
|
|
||||
|
int |
||||
|
dns_parse_txt(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end, |
||||
|
void **result) { |
||||
|
struct dns_rr_txt *ret; |
||||
|
struct dns_parse p; |
||||
|
struct dns_rr rr; |
||||
|
int r, l; |
||||
|
dnsc_t *sp; |
||||
|
dnscc_t *cp, *ep; |
||||
|
|
||||
|
assert(dns_get16(cur+0) == DNS_T_TXT); |
||||
|
|
||||
|
/* first, validate the answer and count size of the result */ |
||||
|
l = 0; |
||||
|
dns_initparse(&p, qdn, pkt, cur, end); |
||||
|
while((r = dns_nextrr(&p, &rr)) > 0) { |
||||
|
cp = rr.dnsrr_dptr; ep = rr.dnsrr_dend; |
||||
|
while(cp < ep) { |
||||
|
r = *cp++; |
||||
|
if (cp + r > ep) |
||||
|
return DNS_E_PROTOCOL; |
||||
|
l += r; |
||||
|
cp += r; |
||||
|
} |
||||
|
} |
||||
|
if (r < 0) |
||||
|
return DNS_E_PROTOCOL; |
||||
|
if (!p.dnsp_nrr) |
||||
|
return DNS_E_NODATA; |
||||
|
|
||||
|
/* next, allocate and set up result */ |
||||
|
l += (sizeof(struct dns_txt) + 1) * p.dnsp_nrr + dns_stdrr_size(&p); |
||||
|
ret = malloc(sizeof(*ret) + l); |
||||
|
if (!ret) |
||||
|
return DNS_E_NOMEM; |
||||
|
ret->dnstxt_nrr = p.dnsp_nrr; |
||||
|
ret->dnstxt_txt = (struct dns_txt *)(ret+1); |
||||
|
|
||||
|
/* and 3rd, fill in result, finally */ |
||||
|
sp = (dnsc_t*)(ret->dnstxt_txt + p.dnsp_nrr); |
||||
|
for(dns_rewind(&p, qdn), r = 0; dns_nextrr(&p, &rr) > 0; ++r) { |
||||
|
ret->dnstxt_txt[r].txt = sp; |
||||
|
cp = rr.dnsrr_dptr; ep = rr.dnsrr_dend; |
||||
|
while(cp < ep) { |
||||
|
l = *cp++; |
||||
|
memcpy(sp, cp, l); |
||||
|
sp += l; |
||||
|
cp += l; |
||||
|
} |
||||
|
ret->dnstxt_txt[r].len = sp - ret->dnstxt_txt[r].txt; |
||||
|
*sp++ = '\0'; |
||||
|
} |
||||
|
dns_stdrr_finish((struct dns_rr_null *)ret, (char*)sp, &p); |
||||
|
*result = ret; |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
struct dns_query * |
||||
|
dns_submit_txt(struct dns_ctx *ctx, const char *name, int qcls, int flags, |
||||
|
dns_query_txt_fn *cbck, void *data) { |
||||
|
return |
||||
|
dns_submit_p(ctx, name, qcls, DNS_T_TXT, flags, |
||||
|
dns_parse_txt, (dns_query_fn *)cbck, data); |
||||
|
} |
||||
|
|
||||
|
struct dns_rr_txt * |
||||
|
dns_resolve_txt(struct dns_ctx *ctx, const char *name, int qcls, int flags) { |
||||
|
return (struct dns_rr_txt *) |
||||
|
dns_resolve_p(ctx, name, qcls, DNS_T_TXT, flags, dns_parse_txt); |
||||
|
} |
@ -0,0 +1,302 @@ |
|||||
|
#include "node.h" |
||||
|
#include "dns.h" |
||||
|
#include "events.h" |
||||
|
|
||||
|
#include <stdlib.h> /* exit() */ |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/socket.h> |
||||
|
#include <arpa/inet.h> |
||||
|
|
||||
|
#include <v8.h> |
||||
|
#include <ev.h> |
||||
|
#include <udns.h> |
||||
|
|
||||
|
using namespace v8; |
||||
|
using namespace node; |
||||
|
|
||||
|
static ev_io io_watcher; |
||||
|
static ev_timer timer_watcher; |
||||
|
|
||||
|
static inline void |
||||
|
set_timeout () |
||||
|
{ |
||||
|
int maxwait = 20; |
||||
|
int wait = dns_timeouts(NULL, maxwait, ev_now(EV_DEFAULT_UC)); |
||||
|
|
||||
|
ev_timer_stop(EV_DEFAULT_UC_ &timer_watcher); |
||||
|
|
||||
|
if (!dns_active(NULL)) { |
||||
|
ev_timer_stop(EV_DEFAULT_UC_ &timer_watcher); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (wait >= 0) { |
||||
|
ev_timer_set(&timer_watcher, (double)wait, 0.0); |
||||
|
ev_timer_start(EV_DEFAULT_UC_ &timer_watcher); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static inline void |
||||
|
maybe_start () |
||||
|
{ |
||||
|
ev_io_start(EV_DEFAULT_UC_ &io_watcher); |
||||
|
set_timeout(); |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
ioevent (EV_P_ ev_io *_watcher, int revents) |
||||
|
{ |
||||
|
assert(revents == EV_READ); |
||||
|
assert(_watcher == &io_watcher); |
||||
|
dns_ioevent(NULL, ev_now(EV_DEFAULT_UC)); |
||||
|
if (!dns_active(NULL)) ev_io_stop(EV_DEFAULT_UC_ &io_watcher); |
||||
|
set_timeout(); |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
timeout (EV_P_ ev_timer *_watcher, int revents) |
||||
|
{ |
||||
|
assert(revents == EV_TIMEOUT); |
||||
|
assert(_watcher == &timer_watcher); |
||||
|
set_timeout(); |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
ResolveError (Promise *promise) |
||||
|
{ |
||||
|
HandleScope scope; |
||||
|
int status = dns_status(NULL); |
||||
|
assert(status < 0); |
||||
|
Local<String> msg = String::New(dns_strerror(status)); |
||||
|
|
||||
|
Local<Value> argv[2] = { Integer::New(status), msg }; |
||||
|
|
||||
|
promise->EmitError(2, argv); |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
AfterResolveA4 (struct dns_ctx *ctx, struct dns_rr_a4 *result, void *data) |
||||
|
{ |
||||
|
assert(ctx == &dns_defctx); |
||||
|
|
||||
|
HandleScope scope; |
||||
|
|
||||
|
Promise *promise = reinterpret_cast<Promise*>(data); |
||||
|
assert(promise); |
||||
|
|
||||
|
if (result == NULL) { |
||||
|
ResolveError(promise); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
/* canonical name */ |
||||
|
Local<String> cname = String::New(result->dnsa4_cname); |
||||
|
|
||||
|
/* Time-To-Live (TTL) value */ |
||||
|
Local<Integer> ttl = Integer::New(result->dnsa4_ttl); |
||||
|
|
||||
|
Local<Array> addresses = Array::New(result->dnsa4_nrr); |
||||
|
for (int i = 0; i < result->dnsa4_nrr; i++) { |
||||
|
HandleScope loop_scope; |
||||
|
|
||||
|
char ip[INET_ADDRSTRLEN]; |
||||
|
inet_ntop(AF_INET, &(result->dnsa4_addr[i]), ip, INET_ADDRSTRLEN); |
||||
|
Local<String> address = String::New(ip); |
||||
|
|
||||
|
addresses->Set(Integer::New(i), address); |
||||
|
} |
||||
|
|
||||
|
Local<Value> argv[3] = { addresses, ttl, cname }; |
||||
|
promise->EmitSuccess(3, argv); |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
AfterResolveA6 (struct dns_ctx *ctx, struct dns_rr_a6 *result, void *data) |
||||
|
{ |
||||
|
assert(ctx == &dns_defctx); |
||||
|
|
||||
|
HandleScope scope; |
||||
|
|
||||
|
Promise *promise = reinterpret_cast<Promise*>(data); |
||||
|
assert(promise); |
||||
|
|
||||
|
if (result == NULL) { |
||||
|
ResolveError(promise); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
/* canonical name */ |
||||
|
Local<String> cname = String::New(result->dnsa6_cname); |
||||
|
|
||||
|
/* Time-To-Live (TTL) value */ |
||||
|
Local<Integer> ttl = Integer::New(result->dnsa6_ttl); |
||||
|
|
||||
|
Local<Array> addresses = Array::New(result->dnsa6_nrr); |
||||
|
for (int i = 0; i < result->dnsa6_nrr; i++) { |
||||
|
HandleScope loop_scope; |
||||
|
|
||||
|
char ip[INET6_ADDRSTRLEN]; |
||||
|
inet_ntop(AF_INET6, &(result->dnsa6_addr[i]), ip, INET6_ADDRSTRLEN); |
||||
|
Local<String> address = String::New(ip); |
||||
|
|
||||
|
addresses->Set(Integer::New(i), address); |
||||
|
} |
||||
|
|
||||
|
Local<Value> argv[3] = { addresses, ttl, cname }; |
||||
|
promise->EmitSuccess(3, argv); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
static Handle<Value> |
||||
|
ResolveA (int type, const Arguments& args) |
||||
|
{ |
||||
|
HandleScope scope; |
||||
|
|
||||
|
if (args.Length() == 0 || !args[0]->IsString()) { |
||||
|
return ThrowException(String::New("Argument must be a string.")); |
||||
|
} |
||||
|
|
||||
|
String::Utf8Value name(args[0]->ToString()); |
||||
|
|
||||
|
Promise *promise = Promise::Create(); |
||||
|
struct dns_query *query; |
||||
|
switch (type) { |
||||
|
case DNS_T_A: |
||||
|
query = dns_submit_a4(NULL, *name, 0, AfterResolveA4, promise); |
||||
|
break; |
||||
|
|
||||
|
case DNS_T_AAAA: |
||||
|
query = dns_submit_a6(NULL, *name, 0, AfterResolveA6, promise); |
||||
|
break; |
||||
|
|
||||
|
default: |
||||
|
return ThrowException(String::New("Unsupported type")); |
||||
|
} |
||||
|
|
||||
|
assert(query); // TODO better error handling.
|
||||
|
|
||||
|
maybe_start(); |
||||
|
|
||||
|
return scope.Close(promise->Handle()); |
||||
|
} |
||||
|
|
||||
|
static Handle<Value> |
||||
|
ResolveA4 (const Arguments& args) |
||||
|
{ |
||||
|
return ResolveA(DNS_T_A, args); |
||||
|
} |
||||
|
|
||||
|
static Handle<Value> |
||||
|
ResolveA6 (const Arguments& args) |
||||
|
{ |
||||
|
return ResolveA(DNS_T_AAAA, args); |
||||
|
} |
||||
|
|
||||
|
static void |
||||
|
AfterReverse (struct dns_ctx *ctx, struct dns_rr_ptr *result, void *data) |
||||
|
{ |
||||
|
assert(ctx == &dns_defctx); |
||||
|
|
||||
|
HandleScope scope; |
||||
|
|
||||
|
Promise *promise = reinterpret_cast<Promise*>(data); |
||||
|
assert(promise); |
||||
|
|
||||
|
if (result == NULL) { |
||||
|
ResolveError(promise); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
/* canonical name */ |
||||
|
Local<String> cname = String::New(result->dnsptr_cname); |
||||
|
|
||||
|
/* Time-To-Live (TTL) value */ |
||||
|
Local<Integer> ttl = Integer::New(result->dnsptr_ttl); |
||||
|
|
||||
|
Local<Array> domains = Array::New(); |
||||
|
|
||||
|
for (int i = 0; i < result->dnsptr_nrr; i++) { |
||||
|
HandleScope loop_scope; |
||||
|
|
||||
|
Local<String> domain = String::New(result->dnsptr_ptr[i]); |
||||
|
domains->Set(Integer::New(i), domain); |
||||
|
} |
||||
|
|
||||
|
Local<Value> argv[3] = { domains, ttl, cname }; |
||||
|
promise->EmitSuccess(3, argv); |
||||
|
} |
||||
|
|
||||
|
static Handle<Value> |
||||
|
Reverse (const Arguments& args) |
||||
|
{ |
||||
|
HandleScope scope; |
||||
|
|
||||
|
if (args.Length() == 0 || !args[0]->IsString()) { |
||||
|
return ThrowException(String::New("Argument must be a string.")); |
||||
|
} |
||||
|
|
||||
|
String::Utf8Value ip_address(args[0]->ToString()); |
||||
|
|
||||
|
union { |
||||
|
struct in_addr addr; |
||||
|
struct in6_addr addr6; |
||||
|
} a; |
||||
|
|
||||
|
bool v4; |
||||
|
|
||||
|
if (dns_pton(AF_INET, *ip_address, &a.addr) > 0) { |
||||
|
v4 = true; |
||||
|
} else if (dns_pton(AF_INET6, *ip_address, &a.addr6) > 0) { |
||||
|
v4 = false; |
||||
|
} else { |
||||
|
return ThrowException(String::New("Invalid IP address")); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
Promise *promise = Promise::Create(); |
||||
|
struct dns_query *query; |
||||
|
|
||||
|
if (v4) { |
||||
|
query = dns_submit_a4ptr(NULL, &a.addr, AfterReverse, promise); |
||||
|
} else { |
||||
|
query = dns_submit_a6ptr(NULL, &a.addr6, AfterReverse, promise); |
||||
|
} |
||||
|
|
||||
|
assert(query); // TODO better error handling.
|
||||
|
|
||||
|
maybe_start(); |
||||
|
|
||||
|
return scope.Close(promise->Handle()); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
DNS::Initialize (Handle<Object> target) |
||||
|
{ |
||||
|
if (dns_init(NULL, 0) < 0) { |
||||
|
fprintf(stderr, "Error initializing UDNS context\n"); |
||||
|
exit(-2); |
||||
|
} |
||||
|
|
||||
|
int fd = dns_open(NULL); |
||||
|
|
||||
|
ev_io_init(&io_watcher, ioevent, fd, EV_READ); |
||||
|
ev_init(&timer_watcher, timeout); |
||||
|
|
||||
|
HandleScope scope; |
||||
|
|
||||
|
target->Set(String::NewSymbol("TEMPFAIL"), Integer::New(DNS_E_TEMPFAIL)); |
||||
|
target->Set(String::NewSymbol("PROTOCOL"), Integer::New(DNS_E_PROTOCOL)); |
||||
|
target->Set(String::NewSymbol("NXDOMAIN"), Integer::New(DNS_E_NXDOMAIN)); |
||||
|
target->Set(String::NewSymbol("NODATA"), Integer::New(DNS_E_NODATA)); |
||||
|
target->Set(String::NewSymbol("NOMEM"), Integer::New(DNS_E_NOMEM)); |
||||
|
target->Set(String::NewSymbol("BADQUERY"), Integer::New(DNS_E_BADQUERY)); |
||||
|
|
||||
|
Local<FunctionTemplate> resolve4 = FunctionTemplate::New(ResolveA4); |
||||
|
target->Set(String::NewSymbol("resolve4"), resolve4->GetFunction()); |
||||
|
|
||||
|
Local<FunctionTemplate> resolve6 = FunctionTemplate::New(ResolveA6); |
||||
|
target->Set(String::NewSymbol("resolve6"), resolve6->GetFunction()); |
||||
|
|
||||
|
Local<FunctionTemplate> reverse = FunctionTemplate::New(Reverse); |
||||
|
target->Set(String::NewSymbol("reverse"), reverse->GetFunction()); |
||||
|
} |
@ -0,0 +1,14 @@ |
|||||
|
#ifndef node_dns_h |
||||
|
#define node_dns_h |
||||
|
|
||||
|
#include <v8.h> |
||||
|
|
||||
|
namespace node { |
||||
|
|
||||
|
class DNS { |
||||
|
public: |
||||
|
static void Initialize(v8::Handle<v8::Object> target); |
||||
|
}; |
||||
|
|
||||
|
} // namespace node
|
||||
|
#endif // node_dns_h
|
@ -0,0 +1,26 @@ |
|||||
|
for (var i = 2; i < ARGV.length; i++) { |
||||
|
var name = ARGV[i] |
||||
|
puts("looking up " + name); |
||||
|
var resolution = node.dns.resolve4(name); |
||||
|
|
||||
|
resolution.addCallback(function (addresses, ttl, cname) { |
||||
|
puts("addresses: " + JSON.stringify(addresses)); |
||||
|
puts("ttl: " + JSON.stringify(ttl)); |
||||
|
puts("cname: " + JSON.stringify(cname)); |
||||
|
|
||||
|
for (var i = 0; i < addresses.length; i++) { |
||||
|
var a = addresses[i]; |
||||
|
var reversing = node.dns.reverse(a); |
||||
|
reversing.addCallback( function (domains, ttl, cname) { |
||||
|
puts("reverse for " + a + ": " + JSON.stringify(domains)); |
||||
|
}); |
||||
|
reversing.addErrback( function (code, msg) { |
||||
|
puts("reverse for " + a + " failed: " + msg); |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
resolution.addErrback(function (code, msg) { |
||||
|
puts("error: " + msg); |
||||
|
}); |
||||
|
} |
Loading…
Reference in new issue