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