mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-09-03 04:13:31 +00:00
Added ADNS library. A nice, versatile DNS client library, which forms the
basis of our DNSAPI implementation. ADNS was written by Ian Jackson (http://www.chiark.greenend.org.uk/~ian/adns/) and was release under the GPL. We are using Jarle Aase's win32 port: (http://adns.jgaa.com/) Arty added timercmp.h, which contains some missing elements from sys/time.h svn path=/trunk/; revision=7110
This commit is contained in:
@@ -0,0 +1,340 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 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.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
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 Program or any portion
|
||||
of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
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 Program, 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 Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) 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; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, 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 executable. However, as a
|
||||
special exception, the source code 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.
|
||||
|
||||
If distribution of executable or 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 counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program 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.
|
||||
|
||||
5. 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 Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program 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 to
|
||||
this License.
|
||||
|
||||
7. 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 Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program 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 Program.
|
||||
|
||||
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.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program 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.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies 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 Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, 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
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. 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 PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
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 program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, 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.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
@@ -0,0 +1,122 @@
|
||||
GPL vs LGPL, in the context of adns
|
||||
-----------------------------------
|
||||
|
||||
Several people have asked me to release GNU adns under the GNU Lesser
|
||||
General Public Licence (LGPL, formerly the Library GPL) instead of the
|
||||
`stronger' GPL. This file is intended to answer most of these
|
||||
questions. If you still have questions or comments, please mail me at
|
||||
<[email protected]>.
|
||||
|
||||
Typically there are two or three kinds of situation where people make
|
||||
this request: the first is where someone is developing a proprietary
|
||||
program and wishes to make use of adns but doesn't wish to make their
|
||||
program free software. The second case is where a free software
|
||||
project is currently using an MIT-like licence or the LGPL and fear
|
||||
`GPL infection'. The third case, which often overlaps with the
|
||||
second, is where another free software project currently using a
|
||||
GPL-incompatible licence, wishes to use adns.
|
||||
|
||||
|
||||
1. Proprietary applications of adns
|
||||
-----------------------------------
|
||||
|
||||
So, let me get this straight. You're writing a proprietary
|
||||
program, by which I mean that you will not be distributing source code
|
||||
and not allowing users to modify and share your software; most likely
|
||||
you are doing this for your own (personal or corporate) financial
|
||||
gain.
|
||||
|
||||
However, you want to take advantage of adns, software which I have
|
||||
spent my time and effort on, and which I release as free software so
|
||||
that everyone can improve, share and use it.
|
||||
|
||||
Don't you think that is a little hypocritical ? I'm sorry, but I
|
||||
don't want you to just take my nice convenient software, without
|
||||
giving something back to the free software community or giving the
|
||||
same rights to your users as I do to you.
|
||||
|
||||
If you really aren't the nasty kind of person I've described here, for
|
||||
example if you have a good reason other than your own selfishness for
|
||||
wanting to restrict distribution of your program, then perhaps you
|
||||
should contact me to discuss it.
|
||||
|
||||
|
||||
2. GPL-avoiding projects (MIT licence, et al)
|
||||
---------------------------------------------
|
||||
|
||||
Some free software projects prefer to avoid the GPL and other licences
|
||||
which force the software always to be free. Instead they use
|
||||
something like the MIT X licence, which allows proprietary versions of
|
||||
their software, or the in the case of some free libraries, the LGPL,
|
||||
which allows proprietary applications. I have to say that I think
|
||||
these people are misguided, but that doesn't mean that they don't have
|
||||
a perfect right to do that.
|
||||
|
||||
Some of these people think that merely writing to an interface
|
||||
provided by GPL'd software will cause their program to become GPL'd
|
||||
too, even if they don't distribute the GPL'd software. I don't think
|
||||
this is the case. I'm perfectly happy for non-GPL'd but
|
||||
GPL-compatible software to refer to adns in its source code. However,
|
||||
I think that exectuables (or compiled libraries) which contain or are
|
||||
dynamically linked against adns must be GPL'd; likewise executable
|
||||
programs (whether compiled or in an interpreted language) which
|
||||
require utilities from adns to function properly must be GPL'd.
|
||||
|
||||
So, you can distribute your non-GPL'd program source which needs adns
|
||||
to compile (provided it's under a GPL-compatible licence), but people
|
||||
who wish to distribute binaries must do so under the terms of the GNU
|
||||
GPL. This may make sense for some GPL-avoiding free software
|
||||
projects; people can still make proprietary programs from your code,
|
||||
provided that they make some provision to replace adns with something
|
||||
whose copyright allows proprietary versions.
|
||||
|
||||
However, this doesn't make much sense for the authors of LGPL'd
|
||||
libraries. All I can say to them is to ask which is more important:
|
||||
that their library be well-constructed and use all the best technology
|
||||
available as free software, or whether it is worth degrading quality
|
||||
of their library in order to allow proprietary programs to use it !
|
||||
|
||||
To help the case of LGPL'd libraries for which adns is not a vital
|
||||
component - for example, a library which provides access to other
|
||||
libraries so that programs which use it need only use certain parts,
|
||||
I have released adns.h (just the public header file) under the LGPL as
|
||||
well as the GPL. See the copyright notice in adns.h for details.
|
||||
Note that this will not help you if it adns is essential to the
|
||||
functioning of your library, because all programs using your library
|
||||
must link against both your library and adns and so must be GPL'd.
|
||||
|
||||
|
||||
For some information and views from the Free Software Foundation on
|
||||
free software licensing, visit:
|
||||
|
||||
Various licenses and comments about them
|
||||
at http://www.fsf.org/philosophy/license-list.html
|
||||
|
||||
Why you shouldn't use the Library GPL for your next library
|
||||
at http://www.fsf.org/philosophy/why-not-lgpl.html
|
||||
|
||||
|
||||
3. GPL-incompatible free software licences
|
||||
------------------------------------------
|
||||
|
||||
Regrettably, there are a number of free software licences (and
|
||||
semi-free licences) in existence which are not compatible with the
|
||||
GPL. That is, they impose restrictions which are not present in the
|
||||
GPL, and therefore distributing a whole work which contains both such
|
||||
a program and a GPL'd program is not possible: either the combination
|
||||
would have to be distributed under the GPL (violating the restrictions
|
||||
made by the original author), or under the GPL-incompatible licence
|
||||
(violating the GPL).
|
||||
|
||||
I may be prepared to make exceptions for such a licence. Please
|
||||
contact me at <[email protected]> with the full text
|
||||
of the GPL-incompatible licence. However, I would usually prefer it
|
||||
if you could use a GPL-compatible licence for your project instead.
|
||||
|
||||
|
||||
-- Ian Jackson 17.9.2000
|
||||
|
||||
|
||||
Local variables:
|
||||
mode: text
|
||||
End:
|
||||
@@ -0,0 +1,130 @@
|
||||
INSTALLATION INSTRUCTIONS for GNU ADNS
|
||||
|
||||
1. Read the security note below.
|
||||
|
||||
2. Standard GNU package build process:
|
||||
$ ./configure [--disable-dynamic] [--prefix=... ...]
|
||||
$ make
|
||||
# make install
|
||||
|
||||
Unfortunately, there is no comprehensive documentation yet. For now,
|
||||
use the comments in the public header file adns.h, and for the C
|
||||
programs their usage messages. If you find this information
|
||||
ambiguous, incomplete or wrong, please report it as a bug.
|
||||
|
||||
|
||||
TESTED PLATFORMS
|
||||
|
||||
The following platforms have been tested at at least some point and
|
||||
should work - please report if they don't:
|
||||
adns version OS
|
||||
1.0 Linux glibc 2.1 (actually tested on Debian 2.2)
|
||||
1.0 Solaris 2.6, 2.7, 2.8 [3]
|
||||
1.0 FreeBSD 3.2, 4.0 (no poll(2), so no adnsresfilter)
|
||||
The following work, but only with --disable-dynamic:
|
||||
1.0 IRIX 6.5 *not* with GCC [1], [2]
|
||||
1.0 AIX 4.1.5
|
||||
1.0 HP-UX 10.20, 11.00
|
||||
Later versions of the same OS should work too. Usually entries in
|
||||
this table mean adns passes its own regression test, when compiled
|
||||
with GCC, and appears to install and run correctly. If you have more
|
||||
information for this table please let me know.
|
||||
|
||||
Notes/known problems:
|
||||
[1] IRIX 6.5 inet_ntoa seems to break with GCC.
|
||||
[2] The SGI IRIX compiler produces many spurious warnings.
|
||||
[3] Dynamically linked, needs some help to find libadns.so.1.0.
|
||||
|
||||
The following platforms are known to be deficient and will not work:
|
||||
Solaris 2.5 Lacks vsnprintf - install glibc ?
|
||||
TruUnix64 (DEC UNIX 4.0f) Lacks vsnprintf - install glibc ?
|
||||
Please don't report these problems unless you have a nice,
|
||||
straightforward solution or workaround for them. (I don't consider
|
||||
including a `vsnprintf' implementation nice, so don't send me one.)
|
||||
|
||||
|
||||
PORTABILITY INFORMATION
|
||||
|
||||
You will find that adns requires a reasonably standard and up to date
|
||||
system. Systems which are neither GNU nor UNIX are not supported.
|
||||
|
||||
The build system assumes by default that you have ELF shared
|
||||
libraries, and that the directory in which libadns.so.1 will be
|
||||
installed is on your dynamic library search path. If your system
|
||||
doesn't have ELF shared libraries then dynamic linking is not
|
||||
supported by adns. Use the --disable-shared configure option.
|
||||
Please don't send me patches to use libtool (which I dislike).
|
||||
|
||||
Compilers other than GNU C should work, but are not well-tested. Feel
|
||||
free to send me patches to improve the situation. However, the
|
||||
Makefiles only know how to use GCC to make dynamic libraries.
|
||||
|
||||
The adnsresfilter utility uses `tsearch' from the C library (a la SVID
|
||||
and X/Open). If you don't have tsearch configure will arranges for
|
||||
adnsresfilter not to be built. To fix this, install a C library
|
||||
containing tsearch, such as the GNU C library. It is best if tsearch
|
||||
uses an automatically-balancing tree algorithm, like the glibc version
|
||||
does. Simple binary trees may perform badly.
|
||||
|
||||
If you change the m4 input files in regress/ you may need GNU m4.
|
||||
|
||||
You will probably find that GNU Make is required.
|
||||
Please do not report this as a bug; install GNU Make instead.
|
||||
|
||||
|
||||
SECURITY AND PERFORMANCE - AN IMPORTANT NOTE
|
||||
|
||||
adns is not a `full-service resolver': it does no caching of responses
|
||||
at all, and has no defence against bad nameservers or fake packets
|
||||
which appear to come from your real nameservers. It relies on the
|
||||
full-service resolvers listed in resolv.conf to handle these tasks.
|
||||
|
||||
For secure and reasonable operation you MUST run a full-service
|
||||
nameserver on the same system as your adns applications, or on the
|
||||
same local, fully trusted network. You MUST only list such
|
||||
nameservers in the adns configuration (eg resolv.conf).
|
||||
|
||||
You MUST use a firewall or other means to block packets which appear
|
||||
to come from these nameservers, but which were actually sent by other,
|
||||
untrusted, entities.
|
||||
|
||||
Furthermore, adns is not DNSSEC-aware in this version; it doesn't
|
||||
understand even how to ask a DNSSEC-aware nameserver to perform the
|
||||
DNSSEC cryptographic signature checking.
|
||||
|
||||
|
||||
COPYRIGHT
|
||||
|
||||
This file, INSTALL, contains installation instructions and other
|
||||
details for adns. It is
|
||||
Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
|
||||
adns is
|
||||
Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
Copyright (C) 1999-2000 Tony Finch <[email protected]> [1]
|
||||
Copyright (C) 1991 Massachusetts Institute of Technology [2]
|
||||
|
||||
adns is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with adns as the file COPYING; if not, email me at the address
|
||||
above or write to the Free Software Foundation, 59 Temple Place -
|
||||
Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
[1] Tony Finch holds the original copyright on client/adnslogres.c and
|
||||
client/fanftest.c, and some modifications to those files.
|
||||
[2] MIT hold the original copyright on the included install-sh,
|
||||
which came via GNU autoconf.
|
||||
|
||||
|
||||
# Local variables:
|
||||
# mode: text
|
||||
# End:
|
||||
@@ -0,0 +1,29 @@
|
||||
# $Id: Makefile,v 1.1 2003/12/18 10:48:20 arty Exp $
|
||||
|
||||
PATH_TO_TOP = ../..
|
||||
|
||||
TARGET_TYPE = library
|
||||
|
||||
TARGET_NAME = adns
|
||||
|
||||
TARGET_CFLAGS = \
|
||||
-MMD -O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
|
||||
-Wstrict-prototypes -Wmissing-prototypes -Wall -DADNS_JGAA_WIN32
|
||||
|
||||
# require os code to explicitly request A/W version of structs/functions
|
||||
TARGET_CFLAGS += -Isrc -Iadns_win32
|
||||
|
||||
TARGET_OBJECTS = \
|
||||
adns_win32/adns_unix_calls.o \
|
||||
src/check.o src/event.o src/general.o src/parse.o src/poll.o \
|
||||
src/query.o src/reply.o src/setup.o src/transmit.o src/types.o
|
||||
|
||||
DEP_OBJECTS = $(TARGET_OBJECTS)
|
||||
|
||||
include $(PATH_TO_TOP)/rules.mak
|
||||
|
||||
include $(TOOLS_PATH)/helper.mk
|
||||
|
||||
include $(TOOLS_PATH)/depend.mk
|
||||
|
||||
# EOF
|
||||
@@ -0,0 +1,77 @@
|
||||
# Makefile - top-level Makefile
|
||||
#
|
||||
# This file is
|
||||
# Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
#
|
||||
# It is part of adns, which is
|
||||
# Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
# Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
# Remember to change ADNS_VERSION_STRING in client/client.h too, and
|
||||
# possibly library soname (MAJOR and MINOR in settings.make.in).
|
||||
DISTVERSION= 1.0
|
||||
|
||||
srcdir= @srcdir@
|
||||
VPATH= @srcdir@
|
||||
|
||||
ENABLE_DYNAMIC= @ENABLE_DYNAMIC@
|
||||
ifeq ($(ENABLE_DYNAMIC),elf)
|
||||
SUBDIRS_DYNAMIC=dynamic
|
||||
else
|
||||
SUBDIRS_DYNAMIC=
|
||||
endif
|
||||
|
||||
SUBDIRS= src $(SUBDIRS_DYNAMIC) client regress
|
||||
|
||||
all install uninstall clean distclean mostlyclean maintainer-clean distprep:
|
||||
set -e; for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done
|
||||
$(MAKE) $@-here
|
||||
|
||||
all-here install-here uninstall-here distprep-here: README
|
||||
|
||||
clean-here mostlyclean-here:
|
||||
rm -f *~ ./#*# core *.orig *.rej adns-*.tar.gz
|
||||
rm -rf dist_tmp
|
||||
|
||||
distclean-here maintainer-clean-here: clean-here
|
||||
rm -f settings.make config.h config.cache config.log config.status
|
||||
|
||||
install-strip:
|
||||
$(MAKE) INSTALL_PROGRAM_FLAGS=-s
|
||||
|
||||
dist_tmp=dist_tmp/adns-$(DISTVERSION)
|
||||
dist: distprep
|
||||
rm -rf dist_tmp*
|
||||
mkdir dist_tmp $(dist_tmp)
|
||||
find \( -name CVS -o -name dist_tmp* \) -prune -o -type d -print | \
|
||||
sed -e 's#.*#mkdir -p $(dist_tmp)/&#' | sh
|
||||
find \( -name CVS -o -name dist_tmp* \) -prune -o -type f -print | \
|
||||
sed -e 's#.*#ln & $(dist_tmp)/&#' | sh
|
||||
$(MAKE) -C dist_tmp/adns-$(DISTVERSION) distclean
|
||||
cd dist_tmp && tar cf ../$(dist_tmp).tar `basename $(dist_tmp)`
|
||||
gzip -9 $(dist_tmp).tar
|
||||
mv $(dist_tmp).tar.gz .
|
||||
|
||||
check: all
|
||||
$(MAKE) -C regress check
|
||||
|
||||
README: README.html
|
||||
lynx -dump -number_links -cfg=/dev/null ./README.html >README.tmp
|
||||
mv -f README.tmp README
|
||||
|
||||
TAGS info dvi:
|
||||
# do nothing
|
||||
@@ -0,0 +1,167 @@
|
||||
|
||||
GNU adns
|
||||
|
||||
Advanced, easy to use, asynchronous-capable DNS client library and
|
||||
utilities.
|
||||
|
||||
adns is a resolver library for C (and C++) programs, and a collection
|
||||
of useful DNS resolver utilities.
|
||||
|
||||
C library
|
||||
|
||||
In contrast with the standard interfaces, gethostbyname et al and
|
||||
libresolv, it has the following features:
|
||||
* It is reasonably easy to use for simple programs which just want
|
||||
to translate names to addresses, look up MX records, etc.
|
||||
* It can be used in an asynchronous, non-blocking, manner. Many
|
||||
queries can be handled simultaneously.
|
||||
* Responses are decoded automatically into a natural representation
|
||||
for a C program - there is no need to deal with DNS packet
|
||||
formats.
|
||||
* Sanity checking (eg, name syntax checking, reverse/forward
|
||||
correspondence, CNAME pointing to CNAME) is performed
|
||||
automatically.
|
||||
* Time-to-live, CNAME and other similar information is returned in
|
||||
an easy-to-use form, without getting in the way.
|
||||
* There is no global state in the library; resolver state is an
|
||||
opaque data structure which the client creates explicitly. A
|
||||
program can have several instances of the resolver.
|
||||
* Errors are reported to the application in a way that distinguishes
|
||||
the various causes of failure properly.
|
||||
* Understands conventional resolv.conf, but this can overridden by
|
||||
environment variables.
|
||||
* Flexibility. For example, the application can tell adns to: ignore
|
||||
environment variables (for setuid programs), disable hostname
|
||||
syntax sanity checks to return arbitrary data, override or ignore
|
||||
resolv.conf in favour of supplied configuration, etc.
|
||||
* Believed to be correct ! For example, will correctly back off to
|
||||
TCP in case of long replies or queries, or to other nameservers if
|
||||
several are available. It has sensible handling of bad responses
|
||||
etc.
|
||||
|
||||
DNS utility programs
|
||||
|
||||
adns also comes with a number of utility programs for use from the
|
||||
command line and in scripts:
|
||||
* adnslogres is a much faster version of Apache's logresolv program.
|
||||
* adnsresfilter is a filter which copies its input to its output,
|
||||
replacing IP addresses by the corresponding names, without unduly
|
||||
delaying the output. For example, you can usefully pipe the output
|
||||
of netstat -n, tcpdump -ln, and the like, into it.
|
||||
* adnshost is a general-purpose DNS lookup utility which can be used
|
||||
easily in from the command line and from shell scripts to do
|
||||
simple lookups. In a more advanced mode it can be used as a
|
||||
general-purpose DNS helper program for scripting languages which
|
||||
can invoke and communicate with subprocesses. See the [1]adnshost
|
||||
usage message for a summary of its capabilities.
|
||||
|
||||
Documentation
|
||||
|
||||
I'm afraid there is no manual yet. However, competent C programmers
|
||||
should be able to use the library based on the [2]commented adns.h
|
||||
header file, and the usage messages for the programs should be
|
||||
sufficient.
|
||||
|
||||
Feedback
|
||||
|
||||
I'd be pleased if you would let me know if you're using my library in
|
||||
your project, and what you think of it.
|
||||
|
||||
If you are subscribed to adns-discuss please send feedback, including
|
||||
bug reports, there; otherwise send mail to
|
||||
[email protected]. If you'd prefer that your
|
||||
message wasn't forwarded to the adns-bugreports list, send it to
|
||||
[email protected].
|
||||
|
||||
Mailinglists
|
||||
|
||||
I have set up mailinglists adns-announce and adns-discuss. The
|
||||
announcements list is moderated and will contain only announcements of
|
||||
important bugs, new versions, etc. The bug reports address mentioned
|
||||
above is also a mailing list; feel free to subscribe to it.
|
||||
|
||||
There are [3]archives and subscription web pages, or you can subscribe
|
||||
by sending mail containing the word `subscribe' to
|
||||
[email protected] or
|
||||
[email protected].
|
||||
|
||||
Download
|
||||
|
||||
Available for download from [4]chiark.greenend.org.uk are:
|
||||
* The [5]current release as a gzipped tarfile.
|
||||
* [6]adns.h API header file with comments, and [7]usage message for
|
||||
adnshost (currently there is no manual, sorry).
|
||||
* All versions released so far are also available via [8]anonymous
|
||||
FTP and [9]HTTP,
|
||||
* A mirror of my CVS repository is available via rsync from
|
||||
rsync.chiark.greenend.org.uk::ftp/users/ian/cvs-pub/adns (use FTP
|
||||
first to find your way around), or via [10]cvsweb.
|
||||
|
||||
adns is also available from the [11]GNU Project FTP servers and their
|
||||
[12]mirrors.
|
||||
|
||||
Technical note
|
||||
|
||||
adns requires a real nameserver like [13]BIND or [14]Dents running on
|
||||
the same system or a nearby one, which must be willing to provide
|
||||
`recursive service'. I.e., adns is a `stub resolver'. All properly
|
||||
configured UN*X and GNU systems will already have such nameserver(s);
|
||||
they are usually listed in /etc/resolv.conf.
|
||||
|
||||
Copyright and licensing
|
||||
|
||||
adns is Copyright 1997-2000 Ian Jackson, Copyright 1999-2000 Tony
|
||||
Finch, and Copyright (C) 1991 Massachusetts Institute of Technology.
|
||||
|
||||
adns is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program and documentation 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
|
||||
[15]GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with adns, or one should be available above; if not, write to
|
||||
the [16]Free Software Foundation, 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA, or email [email protected].
|
||||
_________________________________________________________________
|
||||
|
||||
[17]Ian Jackson / [18][email protected]; more [19]free
|
||||
software by me.
|
||||
|
||||
[20]GNU home page; [21]chiark home page; [22]site or mirror home page
|
||||
|
||||
This web page is Copyright (C)1996-2000 Ian Jackson. See the
|
||||
[23]Copyright/acknowledgements.
|
||||
|
||||
Use any browser - [24]Campaign for a non-browser-specific WWW
|
||||
|
||||
References
|
||||
|
||||
1. http://www.chiark.greenend.org.uk/~ian/adns/adnshost.txt
|
||||
2. http://www.chiark.greenend.org.uk/~ian/adns/adns.h.txt
|
||||
3. http://www.chiark.greenend.org.uk/mailman/listinfo
|
||||
4. http://www.chiark.greenend.org.uk/~ian/adns/
|
||||
5. http://www.chiark.greenend.org.uk/~ian/adns/adns.tar.gz
|
||||
6. http://www.chiark.greenend.org.uk/~ian/adns/adns.h.txt
|
||||
7. http://www.chiark.greenend.org.uk/~ian/adns/adnshost.txt
|
||||
8. ftp://ftp.chiark.greenend.org.uk/users/ian/adns/
|
||||
9. http://www.chiark.greenend.org.uk/~ian/adns/ftp/
|
||||
10. http://www.chiark.greenend.org.uk/ucgi/~ijackson/cvsweb/adns/
|
||||
11. http://www.gnu.org/
|
||||
12. http://www.gnu.org/order/ftp.html
|
||||
13. http://www.isc.org/view.cgi?/products/BIND/index.phtml
|
||||
14. http://www.dents.org/
|
||||
15. http://www.chiark.greenend.org.uk/~ian/COPYING.txt
|
||||
16. http://www.fsf.org/
|
||||
17. http://www.chiark.greenend.org.uk/
|
||||
18. mailto:[email protected]
|
||||
19. http://www.chiark.greenend.org.uk/~ian/software/
|
||||
20. http://www.gnu.org/
|
||||
21. http://www.chiark.greenend.org.uk/
|
||||
22. file://localhost/
|
||||
23. http://www.chiark.greenend.org.uk/~ian/sw-www-copy.html
|
||||
24. http://www.anybrowser.org/campaign/
|
||||
@@ -0,0 +1,222 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>adns - advanced, alternative, asynchronous resolver</title>
|
||||
<link rev="made" href="mailto:[email protected]">
|
||||
</head>
|
||||
<body>
|
||||
<h1>GNU adns</h1>
|
||||
|
||||
<strong>Advanced, easy to use, asynchronous-capable DNS client
|
||||
library and utilities.</strong>
|
||||
|
||||
<!-- Note: this file is maintained in Ian Jackson's private CVS. -->
|
||||
<!-- -->
|
||||
<!-- It is served on the GNU site and also from my own system, -->
|
||||
<!-- under the URL http://www.chiark.greenend.org.uk/adns/ -->
|
||||
<!-- Please ensure that all links continine to be correct -->
|
||||
<!-- both for www.gnu.org and chiark. -->
|
||||
<!-- -->
|
||||
<!-- $Id: README.html,v 1.1 2003/12/18 10:48:20 arty Exp $ -->
|
||||
|
||||
<p>
|
||||
|
||||
adns is a resolver library for C (and C++) programs, and a collection
|
||||
of useful DNS resolver utilities.
|
||||
|
||||
|
||||
<h2>C library</h2>
|
||||
|
||||
In contrast with the standard interfaces, gethostbyname et al and
|
||||
libresolv, it has the following features:
|
||||
|
||||
<ul>
|
||||
|
||||
<li>It is reasonably easy to use for simple programs which just want
|
||||
to translate names to addresses, look up MX records, etc.
|
||||
|
||||
<li>It can be used in an asynchronous, non-blocking, manner. Many
|
||||
queries can be handled simultaneously.
|
||||
|
||||
<li>Responses are decoded automatically into a natural representation
|
||||
for a C program - there is no need to deal with DNS packet formats.
|
||||
|
||||
<li>Sanity checking (eg, name syntax checking, reverse/forward
|
||||
correspondence, CNAME pointing to CNAME) is performed automatically.
|
||||
|
||||
<li>Time-to-live, CNAME and other similar information is returned in
|
||||
an easy-to-use form, without getting in the way.
|
||||
|
||||
<li>There is no global state in the library; resolver state is an
|
||||
opaque data structure which the client creates explicitly. A program
|
||||
can have several instances of the resolver.
|
||||
|
||||
<li>Errors are reported to the application in a way that distinguishes
|
||||
the various causes of failure properly.
|
||||
|
||||
<li>Understands conventional resolv.conf, but this can overridden by
|
||||
environment variables.
|
||||
|
||||
<li>Flexibility. For example, the application can tell adns to:
|
||||
ignore environment variables (for setuid programs), disable hostname
|
||||
syntax sanity checks to return arbitrary data, override or ignore
|
||||
resolv.conf in favour of supplied configuration, etc.
|
||||
|
||||
<li>Believed to be correct ! For example, will correctly back off to
|
||||
TCP in case of long replies or queries, or to other nameservers if
|
||||
several are available. It has sensible handling of bad responses etc.
|
||||
|
||||
</ul>
|
||||
|
||||
<h2>DNS utility programs</h2>
|
||||
|
||||
adns also comes with a number of utility programs for use from the
|
||||
command line and in scripts:
|
||||
|
||||
<ul>
|
||||
|
||||
<li><code>adnslogres</code> is a much faster version of Apache's
|
||||
logresolv program.
|
||||
|
||||
<li><code>adnsresfilter</code> is a filter which copies its input to
|
||||
its output, replacing IP addresses by the corresponding names, without
|
||||
unduly delaying the output. For example, you can usefully pipe the
|
||||
output of netstat -n, tcpdump -ln, and the like, into it.
|
||||
|
||||
<li><code>adnshost</code> is a general-purpose DNS lookup utility
|
||||
which can be used easily in from the command line and from shell
|
||||
scripts to do simple lookups. In a more advanced mode it can be used
|
||||
as a general-purpose DNS helper program for scripting languages which
|
||||
can invoke and communicate with subprocesses. See the
|
||||
<A href="http://www.chiark.greenend.org.uk/~ian/adns/adnshost.txt">adnshost
|
||||
usage message</A> for a summary of its capabilities.
|
||||
|
||||
</ul>
|
||||
|
||||
<h2>Documentation</h2>
|
||||
|
||||
I'm afraid there is no manual yet. However, competent C programmers
|
||||
should be able to use the library based on the
|
||||
<A href="http://www.chiark.greenend.org.uk/~ian/adns/adns.h.txt">commented
|
||||
adns.h header file</A>, and the usage messages for the programs should
|
||||
be sufficient.
|
||||
|
||||
<h2>Feedback</h2>
|
||||
|
||||
I'd be pleased if you would let me know if you're using my library in
|
||||
your project, and what you think of it.
|
||||
|
||||
<p>
|
||||
|
||||
If you are subscribed to <code>adns-discuss</code> please send
|
||||
feedback, including bug reports, there; otherwise send mail to
|
||||
<code>[email protected]</code>. If you'd prefer
|
||||
that your message wasn't forwarded to the <code>adns-bugreports</code>
|
||||
list, send it to <code>[email protected]</code>.
|
||||
|
||||
<h2>Mailinglists</h2>
|
||||
|
||||
I have set up mailinglists <code>adns-announce</code> and
|
||||
<code>adns-discuss</code>. The announcements list is moderated and
|
||||
will contain only announcements of important bugs, new versions, etc.
|
||||
The bug reports address mentioned above is also a mailing list; feel
|
||||
free to subscribe to it.
|
||||
|
||||
<p>
|
||||
|
||||
There are
|
||||
<A href="http://www.chiark.greenend.org.uk/mailman/listinfo">archives
|
||||
and subscription web pages</A>, or you can subscribe by sending mail
|
||||
containing the word `subscribe' to
|
||||
<code>[email protected]</code> or
|
||||
<code>[email protected]</code>.
|
||||
|
||||
<h2>Download</h2>
|
||||
|
||||
Available for download from
|
||||
<A href="http://www.chiark.greenend.org.uk/~ian/adns/">chiark.greenend.org.uk</A>
|
||||
are:
|
||||
<ul>
|
||||
<li>The <A href="http://www.chiark.greenend.org.uk/~ian/adns/adns.tar.gz">current
|
||||
release</A> as a gzipped tarfile.
|
||||
<li><A href="http://www.chiark.greenend.org.uk/~ian/adns/adns.h.txt">adns.h</A>
|
||||
API header file with comments, and
|
||||
<A href="http://www.chiark.greenend.org.uk/~ian/adns/adnshost.txt">usage
|
||||
message for adnshost</A> (currently there is no manual, sorry).
|
||||
<li>All versions released so far are also available via
|
||||
<A href="ftp://ftp.chiark.greenend.org.uk/users/ian/adns/">anonymous
|
||||
FTP</A> and <A href="http://www.chiark.greenend.org.uk/~ian/adns/ftp/">HTTP</A>,
|
||||
<li>A mirror of my CVS repository is available via rsync from
|
||||
<code>rsync.chiark.greenend.org.uk::ftp/users/ian/cvs-pub/adns</code>
|
||||
(use FTP first to find your way around), or via
|
||||
<A href="http://www.chiark.greenend.org.uk/ucgi/~ijackson/cvsweb/adns/">cvsweb</A>.
|
||||
</ul>
|
||||
|
||||
adns is also available from the
|
||||
<A href="http://www.gnu.org/">GNU Project</A> FTP servers and their
|
||||
<A href="http://www.gnu.org/order/ftp.html">mirrors</A>.
|
||||
|
||||
<h2>Technical note</h2>
|
||||
|
||||
adns requires a real nameserver like
|
||||
<A href="http://www.isc.org/view.cgi?/products/BIND/index.phtml">BIND</A>
|
||||
or
|
||||
<A href="http://www.dents.org/">Dents</A> running on
|
||||
the same system or a nearby one, which must be willing to provide
|
||||
`recursive service'. I.e., adns is a `stub resolver'. All properly
|
||||
configured UN*X and GNU systems will already have such nameserver(s);
|
||||
they are usually listed in /etc/resolv.conf.
|
||||
|
||||
<h2>Copyright and licensing</h2>
|
||||
|
||||
<kbd>adns</kbd> is Copyright 1997-2000 Ian Jackson, Copyright
|
||||
1999-2000 Tony Finch, and Copyright (C) 1991 Massachusetts Institute
|
||||
of Technology.
|
||||
|
||||
<p>
|
||||
|
||||
<kbd>adns</kbd> is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
<p>
|
||||
|
||||
This program and documentation is distributed in the hope that it will
|
||||
be useful, but <em>without any warranty</em>; without even the implied
|
||||
warranty of <em>merchantability</em> or <em>fitness for a particular
|
||||
purpose</em>. See the
|
||||
<A href="http://www.chiark.greenend.org.uk/~ian/COPYING.txt">GNU
|
||||
General Public License</A> for more details.
|
||||
|
||||
<p>
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with <kbd>adns</kbd>, or one should be available above; if not,
|
||||
write to the
|
||||
<A href="http://www.fsf.org/">Free Software Foundation</A>,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA,
|
||||
or email <code>[email protected]</code>.
|
||||
|
||||
<p>
|
||||
|
||||
<hr>
|
||||
<A href="http://www.chiark.greenend.org.uk/">Ian Jackson</A> /
|
||||
<A href="mailto:[email protected]"><tt>[email protected]</tt></A>;
|
||||
more <A href="http://www.chiark.greenend.org.uk/~ian/software/">free
|
||||
software</A> by me.
|
||||
<p>
|
||||
|
||||
<A href="http://www.gnu.org/">GNU home page</A>;
|
||||
<A href="http://www.chiark.greenend.org.uk/">chiark home page</A>;
|
||||
<A href="/">site or mirror home page</A>
|
||||
<p>
|
||||
|
||||
This web page is Copyright (C)1996-2000 Ian Jackson. See the
|
||||
<A href="http://www.chiark.greenend.org.uk/~ian/sw-www-copy.html">Copyright/acknowledgements</A>.
|
||||
<p>
|
||||
|
||||
Use any browser -
|
||||
<A href="http://www.anybrowser.org/campaign/">Campaign for a non-browser-specific WWW</A>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,11 @@
|
||||
WISHLIST:
|
||||
* Make timeouts configurable.
|
||||
* `fake' reverse queries (give nnn.nnn.nnn.nnn either always or on error)
|
||||
* `fake' forward queries (allow nnn.nnn.nnn.nnn -> A)
|
||||
* DNSSEC compatibility - be able to retreive KEY and SIG RRs
|
||||
* DNSSEC minimum functionality - ignore Additional when AD set.
|
||||
* IPv6 name<->address translation - but which version ??
|
||||
* IPv6 transport.
|
||||
* Threadsafe version/mode.
|
||||
* Caching in the library.
|
||||
* SRV RRs.
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* acconfig.h
|
||||
* input file for autoheader/autoconf/configure: extra stuff for config.h
|
||||
*/
|
||||
/*
|
||||
* This file is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
*
|
||||
* It is part of adns, which is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
* Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* Define if inline functions a la GCC are available. */
|
||||
#undef HAVE_INLINE
|
||||
|
||||
/* Define if function attributes a la GCC 2.5 and higher are available. */
|
||||
#undef HAVE_GNUC25_ATTRIB
|
||||
|
||||
/* Define if constant functions a la GCC 2.5 and higher are available. */
|
||||
#undef HAVE_GNUC25_CONST
|
||||
|
||||
/* Define if nonreturning functions a la GCC 2.5 and higher are available. */
|
||||
#undef HAVE_GNUC25_NORETURN
|
||||
|
||||
/* Define if printf-format argument lists a la GCC are available. */
|
||||
#undef HAVE_GNUC25_PRINTFFORMAT
|
||||
|
||||
/* Define if we want to include rpc/types.h. Crap BSDs put INADDR_LOOPBACK there. */
|
||||
#undef HAVEUSE_RPCTYPES_H
|
||||
|
||||
@BOTTOM@
|
||||
|
||||
/* Use the definitions: */
|
||||
|
||||
#ifndef HAVE_INLINE
|
||||
#define inline
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POLL
|
||||
#include <sys/poll.h>
|
||||
#else
|
||||
/* kludge it up */
|
||||
struct pollfd { int fd; short events; short revents; };
|
||||
#define POLLIN 1
|
||||
#define POLLPRI 2
|
||||
#define POLLOUT 4
|
||||
#endif
|
||||
|
||||
/* GNU C attributes. */
|
||||
#ifndef FUNCATTR
|
||||
#ifdef HAVE_GNUC25_ATTRIB
|
||||
#define FUNCATTR(x) __attribute__(x)
|
||||
#else
|
||||
#define FUNCATTR(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* GNU C printf formats, or null. */
|
||||
#ifndef ATTRPRINTF
|
||||
#ifdef HAVE_GNUC25_PRINTFFORMAT
|
||||
#define ATTRPRINTF(si,tc) format(printf,si,tc)
|
||||
#else
|
||||
#define ATTRPRINTF(si,tc)
|
||||
#endif
|
||||
#endif
|
||||
#ifndef PRINTFFORMAT
|
||||
#define PRINTFFORMAT(si,tc) FUNCATTR((ATTRPRINTF(si,tc)))
|
||||
#endif
|
||||
|
||||
/* GNU C nonreturning functions, or null. */
|
||||
#ifndef ATTRNORETURN
|
||||
#ifdef HAVE_GNUC25_NORETURN
|
||||
#define ATTRNORETURN noreturn
|
||||
#else
|
||||
#define ATTRNORETURN
|
||||
#endif
|
||||
#endif
|
||||
#ifndef NONRETURNING
|
||||
#define NONRETURNING FUNCATTR((ATTRNORETURN))
|
||||
#endif
|
||||
|
||||
/* Combination of both the above. */
|
||||
#ifndef NONRETURNPRINTFFORMAT
|
||||
#define NONRETURNPRINTFFORMAT(si,tc) FUNCATTR((ATTRPRINTF(si,tc),ATTRNORETURN))
|
||||
#endif
|
||||
|
||||
/* GNU C constant functions, or null. */
|
||||
#ifndef ATTRCONST
|
||||
#ifdef HAVE_GNUC25_CONST
|
||||
#define ATTRCONST const
|
||||
#else
|
||||
#define ATTRCONST
|
||||
#endif
|
||||
#endif
|
||||
#ifndef CONSTANT
|
||||
#define CONSTANT FUNCATTR((ATTRCONST))
|
||||
#endif
|
||||
|
||||
#ifdef HAVEUSE_RPCTYPES_H
|
||||
#include <rpc/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
Vendored
+70
@@ -0,0 +1,70 @@
|
||||
# aclocal.m4 - package-specific macros for autoconf
|
||||
#
|
||||
# This file is
|
||||
# Copyright (C) 1997-1999 Ian Jackson <[email protected]>
|
||||
#
|
||||
# It is part of adns, which is
|
||||
# Copyright (C) 1997-1999 Ian Jackson <[email protected]>
|
||||
# Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
#
|
||||
# This file is part of adns, which is Copyright (C) 1997-1999 Ian Jackson
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
dnl DPKG_CACHED_TRY_COMPILE(<description>,<cachevar>,<include>,<program>,<ifyes>,<ifno>)
|
||||
define(DPKG_CACHED_TRY_COMPILE,[
|
||||
AC_MSG_CHECKING($1)
|
||||
AC_CACHE_VAL($2,[
|
||||
AC_TRY_COMPILE([$3],[$4],[$2=yes],[$2=no])
|
||||
])
|
||||
if test "x$$2" = xyes; then
|
||||
true
|
||||
$5
|
||||
else
|
||||
true
|
||||
$6
|
||||
fi
|
||||
])
|
||||
|
||||
define(ADNS_C_GCCATTRIB,[
|
||||
DPKG_CACHED_TRY_COMPILE(__attribute__((,,)),adns_cv_c_attribute_supported,,
|
||||
[extern int testfunction(int x) __attribute__((,,))],
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_GNUC25_ATTRIB)
|
||||
DPKG_CACHED_TRY_COMPILE(__attribute__((noreturn)),adns_cv_c_attribute_noreturn,,
|
||||
[extern int testfunction(int x) __attribute__((noreturn))],
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_GNUC25_NORETURN),
|
||||
AC_MSG_RESULT(no))
|
||||
DPKG_CACHED_TRY_COMPILE(__attribute__((const)),adns_cv_c_attribute_const,,
|
||||
[extern int testfunction(int x) __attribute__((const))],
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_GNUC25_CONST),
|
||||
AC_MSG_RESULT(no))
|
||||
DPKG_CACHED_TRY_COMPILE(__attribute__((format...)),adns_cv_attribute_format,,
|
||||
[extern int testfunction(char *y, ...) __attribute__((format(printf,1,2)))],
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_GNUC25_PRINTFFORMAT),
|
||||
AC_MSG_RESULT(no)),
|
||||
AC_MSG_RESULT(no))
|
||||
])
|
||||
|
||||
define(ADNS_C_GETFUNC,[
|
||||
AC_CHECK_FUNC([$1],,[
|
||||
AC_CHECK_LIB([$2],[$1],[$3],[
|
||||
AC_MSG_ERROR([cannot find library function $1])
|
||||
])
|
||||
])
|
||||
])
|
||||
@@ -0,0 +1,39 @@
|
||||
This is the ADNS resolver library for Windows, ported
|
||||
by Jarle (jgaa) Aase, [email protected]
|
||||
|
||||
ADNS is not officially suppoted for Windows, but this
|
||||
port provides a 100% native Windows DLL and linker
|
||||
library for the DLL - suitable for traditional compilers
|
||||
and linkers under Windows. The library itself is ported to
|
||||
Microsot Visual C++ 6.0 SP 2.
|
||||
|
||||
The library is tested under Windows 2000, but should work
|
||||
with all versions from Windows NT 4 and up, and Windows98
|
||||
and up. Windows95 is not supported.
|
||||
|
||||
If you want to use the library in your own C/C++ project,
|
||||
you must set the following manifests before including adns.h:
|
||||
|
||||
#define ADNS_MAP_UNIXAPI
|
||||
#define ADNS_DLL
|
||||
|
||||
ADNS_MAP_UNIXAPI will enable the Win32 port in the header-
|
||||
files (else, they will use the defauts for a UNIX system)
|
||||
|
||||
ADNS_DLL will enable linking to the exported DLL functions.
|
||||
Currently I have only made the DLL available. There are two
|
||||
reasons for this:
|
||||
|
||||
1) The DNS protocol is a mess - and it's difficult to make
|
||||
a foolproof implementation. If a security-problem is
|
||||
found (or other bugs) - the fix can usually be deployed
|
||||
just by replacing the DLL.
|
||||
|
||||
2) The GPL/LGPL lisence of ADNS (see GPL-vs-LGPL) will allow
|
||||
you to use the .dll in your project - as far as I can tell.
|
||||
A statically linked version will only be allowed in GPL
|
||||
licensed projects.
|
||||
|
||||
For more information about this port, see http://adns.jgaa.com
|
||||
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
|
||||
/*
|
||||
* adns_unix_calls.c
|
||||
* - Simple implementation of requiered UNIX system calls and
|
||||
* library functions.
|
||||
*/
|
||||
/*
|
||||
* This file is
|
||||
* Copyright (C) 2000, 2002 Jarle (jgaa) Aase <[email protected]>
|
||||
*
|
||||
* It is part of adns, which is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
* Copyright (C) 1999 Tony Finch <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#include "adns.h"
|
||||
|
||||
int adns_writev(int FileDescriptor, const struct iovec * iov, int iovCount)
|
||||
{
|
||||
size_t total_len = 0;
|
||||
int bytes_written = 0;
|
||||
int i = 0, r = 0;
|
||||
char *buf = NULL, *p = NULL;
|
||||
|
||||
for(; i < iovCount; i++)
|
||||
total_len += iov[i].iov_len;
|
||||
|
||||
p = buf = (char *)alloca(total_len);
|
||||
|
||||
for(; i < iovCount; i++)
|
||||
{
|
||||
memcpy(p, iov[i].iov_base, iov[i].iov_len);
|
||||
p += iov[i].iov_len;
|
||||
}
|
||||
|
||||
ADNS_CLEAR_ERRNO
|
||||
r = send(FileDescriptor, buf, total_len, 0);
|
||||
ADNS_CAPTURE_ERRNO;
|
||||
return r;
|
||||
}
|
||||
|
||||
int adns_inet_aton(const char *cp, struct in_addr *inp)
|
||||
{
|
||||
inp->s_addr = inet_addr(cp);
|
||||
return inp->s_addr != INADDR_ANY;
|
||||
}
|
||||
|
||||
int adns_getpid()
|
||||
{
|
||||
return GetCurrentProcessId();
|
||||
}
|
||||
|
||||
int gettimeofday(struct timeval *tv, struct timezone *tz)
|
||||
{
|
||||
static __int64 Adjustment;
|
||||
__int64 Now = 0;
|
||||
|
||||
if (!Adjustment)
|
||||
{
|
||||
SYSTEMTIME st = {1970,1,3,0,0,0,0};
|
||||
SystemTimeToFileTime(&st, (LPFILETIME)Adjustment);
|
||||
}
|
||||
|
||||
if (tz)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
GetSystemTimeAsFileTime((LPFILETIME)&Now);
|
||||
Now -= Adjustment;
|
||||
|
||||
tv->tv_sec = (long)(Now / 100000000);
|
||||
tv->tv_usec = (long)((Now / 100) - (((__int64)tv->tv_sec * 1000) * 100));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Memory allocated in the DLL must be freed in the dll, so
|
||||
we provide memory manegement functions. */
|
||||
|
||||
#ifdef ADNS_DLL
|
||||
|
||||
#undef malloc
|
||||
#undef realloc
|
||||
#undef free
|
||||
|
||||
void *adns_malloc(const size_t bytes)
|
||||
{
|
||||
return malloc(bytes);
|
||||
}
|
||||
|
||||
void *adns_realloc(void *ptr, const size_t bytes)
|
||||
{
|
||||
return realloc(ptr, bytes);
|
||||
}
|
||||
|
||||
void adns_free(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
#endif /* ADNS_DLL */
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
*
|
||||
* This file is
|
||||
* Copyright (C) 2000, 2002 Jarle (jgaa) Aase <[email protected]>
|
||||
*
|
||||
* It is part of adns, which is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
* Copyright (C) 1999 Tony Finch <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* For the benefit of certain LGPL'd `omnibus' software which provides
|
||||
* a uniform interface to various things including adns, I make the
|
||||
* following additional licence. I do this because the GPL would
|
||||
* otherwise force either the omnibus software to be GPL'd or for the
|
||||
* adns-using part to be distributed separately.
|
||||
*
|
||||
* So, you may also redistribute and/or modify adns.h (but only the
|
||||
* public header file adns.h and not any other part of adns) under the
|
||||
* terms of the GNU Library General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Note that adns itself is GPL'd. Authors of adns-using applications
|
||||
* with GPL-incompatible licences, and people who distribute adns with
|
||||
* applications where the whole distribution is not GPL'd, are still
|
||||
* likely to be in violation of the GPL. Anyone who wants to do this
|
||||
* should contact Ian Jackson. Please note that to avoid encouraging
|
||||
* people to infringe the GPL as it applies the body of adns, Ian thinks
|
||||
* that if you take advantage of the special exception to redistribute
|
||||
* just adns.h under the LGPL, you should retain this paragraph in its
|
||||
* place in the appropriate copyright statements.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License,
|
||||
* or the GNU Library General Public License, as appropriate, along
|
||||
* with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ADNS_WIN32_H_INCLUDED
|
||||
#define ADNS_WIN32_H_INCLUDED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#if defined(ADNS_DLL)
|
||||
# ifdef ADNS_DLL_EXPORTS
|
||||
# define ADNS_API __declspec(dllexport)
|
||||
# else
|
||||
# define ADNS_API __declspec(dllimport)
|
||||
# endif /* ADNS_EXPORTS */
|
||||
#else
|
||||
# define ADNS_API
|
||||
#endif /* ADNS_DLL */
|
||||
|
||||
#if defined (_MSC_VER)
|
||||
#pragma warning(disable:4003)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
/* ---------------- START OF C HEADER -------------- */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <Winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <malloc.h>
|
||||
#include <signal.h>
|
||||
|
||||
#define HAVE_WINSOCK 1
|
||||
//#define PRINTFFORMAT(si,tc)
|
||||
#define inline __inline
|
||||
|
||||
#define ADNS_SOCKET SOCKET
|
||||
#define adns_socket_close(sck) closesocket(sck)
|
||||
#define adns_socket_read(sck, data, len) recv(sck, (char *)data, len, 0)
|
||||
#define adns_socket_write(sck, data, len) send(sck, (char *)data, len, 0)
|
||||
|
||||
/* Win32 does not set errno on Winsock errors(!)
|
||||
* We have to map the winsock errors to errno manually
|
||||
* in order to support the original UNIX error hadnlig
|
||||
*/
|
||||
#define ADNS_CAPTURE_ERRNO {errno = WSAGetLastError(); WSASetLastError(errno);}
|
||||
#define ADNS_CLEAR_ERRNO {WSASetLastError(errno = 0);}
|
||||
|
||||
#define ENOBUFS WSAENOBUFS
|
||||
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||
#define EINPROGRESS WSAEINPROGRESS
|
||||
#define EMSGSIZE WSAEMSGSIZE
|
||||
#define ENOPROTOOPT WSAENOPROTOOPT
|
||||
//#define NONRETURNING
|
||||
//#define NONRETURNPRINTFFORMAT(si,tc)
|
||||
|
||||
/*
|
||||
* UNIX system API for Win32
|
||||
* The following is a quick and dirty implementation of
|
||||
* some UNIX API calls in Win32.
|
||||
* They are used in the dll, but if your project have
|
||||
* it's own implementation of these system calls, simply
|
||||
* undefine ADNS_MAP_UNIXAPI.
|
||||
*/
|
||||
|
||||
struct iovec
|
||||
{
|
||||
char *iov_base;
|
||||
int iov_len;
|
||||
};
|
||||
|
||||
struct timezone; /* XXX arty */
|
||||
|
||||
/*
|
||||
* Undef ADNS_MAP_UNIXAPI in the calling code to use natve calls
|
||||
*/
|
||||
ADNS_API int adns_gettimeofday(struct timeval *tv, struct timezone *tz);
|
||||
ADNS_API int adns_writev (int FileDescriptor, const struct iovec * iov, int iovCount);
|
||||
ADNS_API int adns_inet_aton(const char *cp, struct in_addr *inp);
|
||||
ADNS_API int adns_getpid();
|
||||
|
||||
#ifdef ADNS_DLL
|
||||
ADNS_API void *adns_malloc(const size_t bytes);
|
||||
ADNS_API void *adns_realloc(void *ptr, const size_t bytes);
|
||||
ADNS_API void adns_free(void *ptr);
|
||||
#endif
|
||||
|
||||
#define gettimeofday(tv, tz) adns_gettimeofday(tv, tz)
|
||||
#define writev(FileDescriptor, iov, iovCount) adns_writev(FileDescriptor, iov, iovCount)
|
||||
#define inet_aton(ap, inp) adns_inet_aton(ap, inp)
|
||||
#define getpid() adns_getpid()
|
||||
|
||||
#ifdef ADNS_DLL
|
||||
# define malloc(bytes) adns_malloc(bytes)
|
||||
# define realloc(ptr, bytes) adns_realloc(ptr, bytes)
|
||||
# define free(ptr) adns_free(ptr)
|
||||
#endif
|
||||
|
||||
/* ---------------- END OF C HEADER -------------- */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#include "timercmp.h" /* arty added: mingw headers don't seem to have it */
|
||||
|
||||
#endif /* ADNS_WIN32_H_INCLUDED */
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
|
||||
/* jgaa oct 9th 2000: Found this on www.
|
||||
* No copyright information given.
|
||||
* Slightly modidied.
|
||||
*
|
||||
* Origin: http://www.winsite.com/info/pc/win3/winsock/sossntr4.zip/SOSSNT/SRC/GETOPT.C.html
|
||||
*/
|
||||
|
||||
/* got this off net.sources */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "getopt.h"
|
||||
|
||||
|
||||
/*
|
||||
* get option letter from argument vector
|
||||
*/
|
||||
int opterr = 1, /* useless, never set or used */
|
||||
optind = 1, /* index into parent argv vector */
|
||||
optopt; /* character checked for validity */
|
||||
char* optarg; /* argument associated with option */
|
||||
|
||||
#define BADCH (int)'?'
|
||||
#define EMSG ""
|
||||
#define tell(s) fputs(*argv,stderr);fputs(s,stderr); \
|
||||
fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);
|
||||
|
||||
int getopt(int argc, char * const *argv, const char *optstring)
|
||||
{
|
||||
static char *place = EMSG; /* option letter processing */
|
||||
register char *oli; /* option letter list index */
|
||||
|
||||
if(!*place) { /* update scanning pointer */
|
||||
if(optind >= argc || *(place = argv[optind]) != '-' || !*++place)
|
||||
return(EOF);
|
||||
if (*place == '-') { /* found "--" */
|
||||
++optind;
|
||||
return(EOF);
|
||||
}
|
||||
} /* option letter okay? */
|
||||
if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(optstring,optopt)))
|
||||
{
|
||||
if(!*place) ++optind;
|
||||
tell(": illegal option -- ");
|
||||
}
|
||||
if (*++oli != ':') { /* don't need argument */
|
||||
optarg = NULL;
|
||||
if (!*place) ++optind;
|
||||
}
|
||||
else { /* need an argument */
|
||||
if (*place) optarg = place; /* no white space */
|
||||
else if (argc <= ++optind) { /* no arg */
|
||||
place = EMSG;
|
||||
tell(": option requires an argument -- ");
|
||||
}
|
||||
else optarg = argv[optind]; /* white space */
|
||||
place = EMSG;
|
||||
++optind;
|
||||
}
|
||||
return(optopt); /* dump back option letter */
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
#ifndef GETOPT_H
|
||||
#define GETOPT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int opterr; /* useless, never set or used */
|
||||
extern int optind; /* index into parent argv vector */
|
||||
extern int optopt; /* character checked for validity */
|
||||
extern char* optarg; /* argument associated with option */
|
||||
|
||||
int getopt(int argc, char * const *argv, const char *optstring);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* GETOPT_H */
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef TIMERCMP_H
|
||||
#define TIMERCMP_H
|
||||
|
||||
/* Taken from sys/time.h on linux. */
|
||||
# define timercmp(a, b, CMP) \
|
||||
(((a)->tv_sec == (b)->tv_sec) ? \
|
||||
((a)->tv_usec CMP (b)->tv_usec) : \
|
||||
((a)->tv_sec CMP (b)->tv_sec))
|
||||
|
||||
# define timerclear(a) ((a)->tv_sec = (a)->tv_usec = 0)
|
||||
|
||||
#endif//TIMERCMP_H
|
||||
@@ -0,0 +1,284 @@
|
||||
adns (1.0); urgency=medium
|
||||
|
||||
Bugfixes:
|
||||
* Treat 8-bit characters in email addrs as RFC822 `special' (=> quote).
|
||||
* Fix incorrect `compressed datagram contains loop' error.
|
||||
* Actually compile shared libraries by default !
|
||||
* Fix adnsresfilter usage message to include correct default timeout.
|
||||
|
||||
General improvements:
|
||||
* adnshost, adnslogres, adnsresfilter have options for config override.
|
||||
* adnsresfilter has --debug option.
|
||||
* Improvements to adnslogres (incl. new -c option) from Tony Finch.
|
||||
* adnslogres has --help option, all utilities support --version.
|
||||
* Documentation improved somewhat, including new GPL-vs-LGPL file.
|
||||
|
||||
Changes for non-BETA release:
|
||||
* Change shared library soname to 1.0.
|
||||
* Do not install adnstest test utility.
|
||||
|
||||
Regression test improvements:
|
||||
* Tests now include adnshost, adnslogres and adnsresfilter.
|
||||
* Test cancellation both before and after query completion.
|
||||
|
||||
Portability fixes and cleanups:
|
||||
* adnstest: setvbuf(stdout,...) before we do first output.
|
||||
* Cope with compilers that don't do `inline'.
|
||||
* Add and fix various missing system #includes.
|
||||
* Find install-sh properly when we need to use it, and chmod it +x.
|
||||
* Do not use variadic macro, use stdarg instead (adnslogres.c).
|
||||
* Regression tests work even if some syscalls are already macros.
|
||||
* #include "config.h" before "adns.h".
|
||||
* Cast a sizeof(...) in src/event.c to unsigned long before printing.
|
||||
* Add pre-generated versions of m4-generated files in regress/.
|
||||
* Kill bogus warning, adh-main.c: `arg2' might be used uninitialized ...
|
||||
* Add extra {...} near adnslogres.c:167 to kill spurious warning.
|
||||
* Use `printf' instead of `echo -n'.
|
||||
* Add list of tested platforms in INSTALL file.
|
||||
|
||||
-- Ian Jackson <[email protected]> Sun, 17 Sep 2000 15:15:58 +0100
|
||||
|
||||
adns (0.9) BETA; urgency=high
|
||||
|
||||
Bug fixes:
|
||||
* Don't make _processany always kill the TCP connection with the message
|
||||
`TCP connection failed: poll/select: exceptional condition detected'.
|
||||
* Call MEM_ROUND in __transfer_interim (avoids assert fail
|
||||
`qu->interim_allocd>=0' on some platforms eg 64 bit).
|
||||
* adnsresfilter doesn't resolve textual prefixes of addresses (eg,
|
||||
10.0.0.1 out of 10.0.0.123) if input happens to block at that point.
|
||||
* Do not spin if TCP connection blocks for writing (and add test case).
|
||||
* Fail queries if TCP dies repeatedly, rather than retrying many times.
|
||||
* Do not abort in a couple of places if TCP unexpectedly broken.
|
||||
* Do not free something twice if query fails and is then cancelled.
|
||||
|
||||
Portability/compilation fixes:
|
||||
* Move `extern "C" {' to after #include <...>'s.
|
||||
* Pass LDFLAGS from configure on to ld via settings.make.in.
|
||||
* make clean deletes *.so and *.so.* files.
|
||||
* New --disable-dynamic configure option for non-ELF systems.
|
||||
* Use AC_PROG_INSTALL (=> perhaps install-sh), to avoid bad `install'.
|
||||
|
||||
Minor improvements:
|
||||
* Do not print warning if sendto() gives EAGAIN.
|
||||
* adnsresfilter default timeout changed to 1000ms.
|
||||
* m1test script can invoke `hrecord' differently.
|
||||
* regress/output-<case>.report file contains more useful info.
|
||||
* TODO list and other docs updated slightly.
|
||||
* Referrals with RD+RA set, or RCODE=Refused, don't generate warnings,
|
||||
just debug messages. BIND does this kind of thing all the time.
|
||||
|
||||
-- Ian Jackson <[email protected]> Wed, 9 Aug 2000 16:59:28 +0100
|
||||
|
||||
adns (0.8) BETA; urgency=medium
|
||||
|
||||
Bugfixes:
|
||||
* Race near adns_beforeselect which could cause infinite timeout fixed
|
||||
(it's now less agressive, and will more often return a zero timeout.)
|
||||
* Fixed infrequent race causing assertion failure in adns__tcp_broken
|
||||
`ads->tcpstate == server_connecting || ads->tcpstate == server_ok'.
|
||||
* Spurious `server failure on unidentifiable query' warning suppressed.
|
||||
* If we get a referral, don't also always complain falsely about RD==0.
|
||||
* adnslogres: cast chars to unsigned char before using ctype.h macros.
|
||||
* In _beforeselect, global failure now means zero timeout, and in
|
||||
tcp_events, really never try to do anything with the TCP connection if
|
||||
act is zero. This might possibly cause an infinite delay (ie, lockup)
|
||||
if things go badly wrong *and* a really unlikely race happens.
|
||||
* Test suite `lines of syscall left' value is correct; !0 is failure.
|
||||
|
||||
Portability fixes:
|
||||
* install-sh (from autoconf 2.12 Debian r13) included.
|
||||
* adnslogres: do not call equivalent of printf("%.*s",0,(char*)0).
|
||||
|
||||
Documentation improvements:
|
||||
* Security/performance note added, about local nameservers and DNSSEC.
|
||||
* Documented that adns_rr_info _rr_hostaddr ( ) for address list
|
||||
means permanent failure, and ? means temporary failure.
|
||||
* Typo (*now for now in _beforeselect description) in adns.h fixed.
|
||||
* Copyright notices updated.
|
||||
|
||||
Changes to produce more defensive code:
|
||||
* In adns_wait, assert that the timeout is not infinite.
|
||||
* Make qu->id start out as -2 when initially allocated.
|
||||
|
||||
-- Ian Jackson <[email protected]> Sun, 7 May 2000 23:37:13 +0100
|
||||
|
||||
adns (0.7) BETA; urgency=medium
|
||||
|
||||
* New adns_submit_reverse_any for eg RBL lookups, and corresponding
|
||||
option to adnshost.
|
||||
* README updated (from www home page).
|
||||
|
||||
* In answers, quote all except alphanums and - _ / + (and document).
|
||||
* Don't reject specials in cnames even without adns_qf_quotefail_cname.
|
||||
* Better checking of long domain names and labels in queries.
|
||||
* answer->owner may be null on error. Documented, and adnshost copes.
|
||||
* Better reporting of unexpected or weird replies from nameserver.
|
||||
* Add test case for recursion (infinite loop) domain compression.
|
||||
|
||||
-- Ian Jackson <[email protected]> Thu, 2 Mar 2000 01:55:53 +0000
|
||||
|
||||
adns (0.6) BETA; urgency=high
|
||||
|
||||
Core library bugfixes:
|
||||
* Avoid infinite timeouts, causing lockup, when they should be zero !
|
||||
* TCP handling revamped (avoids undefined behaviour due to reentrancy).
|
||||
* Do not fail assertion if _qf_owner, _qf_search, domain ends in `.'.
|
||||
* Many memory leaks fixed.
|
||||
|
||||
Cool new utility:
|
||||
* adnsresfilter is like `cat' but converts addresses to names without
|
||||
delaying the output. Pipe `netstat -n', `tcpdump -ln', etc. into it.
|
||||
|
||||
Test and client program bug and portability fixes:
|
||||
* Dynamic library building works properly.
|
||||
* adnshost prints somewhat better messages about some wrong usages.
|
||||
* Include <stdlib.h> and <sys/types.h> in adnshost.h.
|
||||
* adnslogres: parsing and error checking improved (Tony Finch).
|
||||
* Regression tests can cope with zero-length reads.
|
||||
* Regression tests check for memory leaks.
|
||||
* adnstest copes with empty query type list.
|
||||
* adnstest uninitialised memory bug fixed.
|
||||
|
||||
General improvements
|
||||
* Better control of adnshost output and error messages (new -F options).
|
||||
* New adns_if_logpid option (functionality suggested by Tony Finch).
|
||||
* New fanftest test program from Tony Finch (ignored by `make install').
|
||||
* Reads /etc/resolv-adns.conf if it exists.
|
||||
* Declare flags parameters as enums again, not ints.
|
||||
|
||||
-- Ian Jackson <[email protected]> Wed, 24 Nov 1999 17:13:03 +0000
|
||||
|
||||
adns (0.5) unstable; urgency=high
|
||||
|
||||
New features:
|
||||
* adnslogres, ~100x faster replacement for Apache logresolve;
|
||||
Thanks to Tony Finch for the program and the performance figure.
|
||||
* Internal consistency checking with assert if right options set.
|
||||
* adns_wait_poll function like adns_wait but uses poll, not select.
|
||||
* adns_reverse_submit function for easy in-addr queries.
|
||||
* adns_errtypeabbrev funcion for getting eg "permfail" from _s_nodata.
|
||||
* adnshost utility for scripts and the like (rather alpha).
|
||||
|
||||
Incompatible changes:
|
||||
* RRs with mailboxes never rejected due to strange chars if _raw.
|
||||
* Lack of a mailbox produces `.' not `<>'.
|
||||
* Better usage messages (and no default query domain) for adnstest.
|
||||
* Return EAGAIN from _check instead of EWOULDBLOCK.
|
||||
* adns_rr_info on _r_mx etc. shows status type abbrev and status number.
|
||||
|
||||
Bugfixes:
|
||||
* Do not invoke __autosys indirectly from __procdgram (result: coredump
|
||||
usually in memmove, unless adns_if_noautosys was used).
|
||||
* Do not scramble innards when a query on the output queue is cancelled.
|
||||
* Do not close tcp socket twice.
|
||||
* Mailboxes containing spaces in their names are quoted.
|
||||
* Give ESRCH, not EAGAIN, if _check called with no queries outstanding.
|
||||
* adns_rr_hostaddr naddrs is -1 on temporary failure (as documented).
|
||||
* Reject TXT RRs with no strings.
|
||||
* Correct error messages for qname CNAME foo, foo CNAME bar.
|
||||
* adns_processany actually does something.
|
||||
* Fixed typos in adns.h.
|
||||
|
||||
General improvements:
|
||||
* Promise not to change fds in adns_beforepoll (if now is specified).
|
||||
* Improved textual error string for _s_prohibitedcname.
|
||||
* New comment in adns_processany and return 0 (not r which is 0).
|
||||
* Documentation of resolv.conf directives and options, and of environment
|
||||
variables understood, in adns.h
|
||||
* Regression test scripts set EF_DISABLE_BANNER (for Electric Fence).
|
||||
|
||||
Portability and build improvements:
|
||||
* Give install the '-c' flag (otherwise some delete the original !).
|
||||
* Do not remove top-level Makefile on `make clean'.
|
||||
* Don't complain so much about poll(2) tests if not available.
|
||||
* Do not give -u 0 -g 0 options to install.
|
||||
* Remove trailing , from some enums in adns.h.
|
||||
* Dynamically linked clients now made with -l, so as to avoid rpath.
|
||||
* Do not use $^ in make rules (should help with non-GNU make).
|
||||
* Declare flags parameters as ints not enums because C++ is crap.
|
||||
|
||||
-- Ian Jackson <[email protected]> Wed, 13 Oct 1999 02:24:35 +0100
|
||||
|
||||
adns (0.4) unstable; urgency=high
|
||||
|
||||
General important bugfixes:
|
||||
* make _qf_owner work if _qf_search not specified, and test it (oops!)
|
||||
* ads->configerrno now initialised (in setup.c).
|
||||
* timercmp(,,<=) doesn't work - use !timercmp(,,>).
|
||||
* Changed memory semantics of internal queries to fix bugs.
|
||||
* Restarting a TCP-using query (eg due to CNAME) doesn't abort.
|
||||
|
||||
Fixes for handling of broken kinds of reply:
|
||||
* Only accept a reply from the subset of servers we sent the query.
|
||||
* Ignore CNAME(s) in answer after RR(s) (and test).
|
||||
|
||||
Other bugfixes and improvements:
|
||||
* adns_s_systemfail is in table of errors (for eg adns_strerror).
|
||||
* Do not ship config.cache, Makefile, etc.
|
||||
* Improvements to install instructions, TODO, etc.
|
||||
* Regression tests compile on systems without poll(2).
|
||||
* Do not install adnstest_s.
|
||||
* _submit returns ENOSYS, not adns_s_unknownquery; documented, tested.
|
||||
* <adns.h> includes <sys/types.h>, <sys/time.h>, <unistd.h>.
|
||||
|
||||
-- Ian Jackson <[email protected]> Thu, 5 Aug 1999 01:17:38 +0100
|
||||
|
||||
adns (0.3) unstable; urgency=low
|
||||
|
||||
Incompatible changes:
|
||||
* Low adns_status values (below adns_s_max_tempfail) renumbered to make
|
||||
room for future locally-induced and locally-detected errors.
|
||||
* Event loop functions for use by select(2) renamed and tidied up.
|
||||
|
||||
Features / improvements:
|
||||
* New adns_errabbrev() for getting status abbreviation strings.
|
||||
* regress/checkall prints summary list of failed tests, if any.
|
||||
* Event loop functions for poll(2), and some raw variants.
|
||||
* adnstest has ability to use poll(2), and user can set initflags.
|
||||
* checkall prints passed list as well as failed list, if any failed.
|
||||
* You can iterate over outstanding queries (but only once at a time).
|
||||
|
||||
Bugfixes:
|
||||
* Non-RFC822 mailbox `domain' formatting now works, and clarified.
|
||||
* Rejection of bad characters in domains (without quoteok) works.
|
||||
* Clean up parents from adns->childw (otherwise would abort/segfault).
|
||||
* In adnstest, allocate enough space for, and terminate, query types.
|
||||
* In adnstest, don't print errno values as adns_status values.
|
||||
|
||||
* Added TODO file.
|
||||
* Made adnstest.c test context pointers.
|
||||
|
||||
-- Ian Jackson <[email protected]> Thu, 15 Jul 1999 00:23:12 +0100
|
||||
|
||||
adns (0.2) experimental; urgency=low
|
||||
|
||||
Portability fixes for compilation on various platforms:
|
||||
* Include <sys/socket.h> and <netinet/in.h> in files with <arpa/inet.h>.
|
||||
* Don't use GCC union assignment feature (.rrs=0 => .rrs.untyped=0).
|
||||
* Explictly cast things to [const] struct sockaddr* in syscall args.
|
||||
* Check whether we need -lsocket.
|
||||
* Include <sys/times.h> in a few more files.
|
||||
* Include <unistd.h> and <sys/time.h> for select.
|
||||
* Look for inet_aton and inet_ntoa (in -lnsl and -lsocket).
|
||||
* LDLIBS removed from dependency lists (some makes don't support this).
|
||||
* An `ambiguous else' warning from some compilers in types.c is removed.
|
||||
|
||||
Other changes:
|
||||
* Added COPYING (copy of the GPL).
|
||||
* Regression test failure output improved.
|
||||
* Missing targets in regress/Makefile.in added.
|
||||
* Regression test doesn't rely on value of fcntl flags eg O_NONBLOCK.
|
||||
|
||||
-- Ian Jackson <[email protected]> Thu, 20 May 1999 00:27:32 +0100
|
||||
|
||||
adns (0.1) experimental; urgency=low
|
||||
|
||||
* Initial public alpha release.
|
||||
|
||||
-- Ian Jackson <[email protected]> Sat, 17 April 1999 17:42:19
|
||||
|
||||
Local variables:
|
||||
mode: debian-changelog
|
||||
fill-column: 75
|
||||
End:
|
||||
@@ -0,0 +1,82 @@
|
||||
# client/Makefile - client program(s) Makefile
|
||||
#
|
||||
# This file is
|
||||
# Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
#
|
||||
# It is part of adns, which is
|
||||
# Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
# Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
srcdir= @srcdir@
|
||||
VPATH= @srcdir@
|
||||
|
||||
PROGS_SYSDEP= @PROGS_HAVE_TSEARCH@
|
||||
ENABLE_DYNAMIC= @ENABLE_DYNAMIC@
|
||||
|
||||
PROGRAMS= adnslogres adnshost $(PROGS_SYSDEP)
|
||||
PROGRAMS_LOCAL= fanftest adnstest
|
||||
PROGRAMS_ALL= $(PROGRAMS) $(PROGRAMS_LOCAL)
|
||||
|
||||
STATIC_LIB= $(ADNSDIR)/libadns.a
|
||||
|
||||
ifeq ($(ENABLE_DYNAMIC),elf)
|
||||
DYNAMIC_DEP= $(srcdir)/../dynamic/$(SHLIBFILE)
|
||||
DYNAMIC_LINK= -L$(srcdir)/../dynamic -ladns
|
||||
DYNAMIC_SUFFIX= _s
|
||||
else
|
||||
DYNAMIC_DEP= $(STATIC_LIB)
|
||||
DYNAMIC_LINK= $(STATIC_LIB)
|
||||
DYNAMIC_SUFFIX=
|
||||
endif
|
||||
|
||||
TARG_INSTALL= $(PROGRAMS)
|
||||
TARG_LOCAL= $(addsuffix $(DYNAMIC_SUFFIX), $(PROGRAMS_ALL))
|
||||
TARGETS= $(TARG_LOCAL) $(TARG_INSTALL)
|
||||
include $(srcdir)/../settings.make
|
||||
|
||||
DIRCFLAGS= -I$(srcdir)/../src
|
||||
|
||||
TARG_OBJS= $(addsuffix .o, $(PROGRAMS_ALL))
|
||||
ADH_OBJS= adh-main.o adh-opts.o adh-query.o
|
||||
ALL_OBJS= $(ADH_OBJS) $(TARG_OBJS)
|
||||
|
||||
ADNSDIR= $(srcdir)/../src/
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
install: $(TARG_INSTALL)
|
||||
set -xe; for f in $(TARG_INSTALL); \
|
||||
do $(INSTALL_PROGRAM) $$f $(bin_dir)/$$f; done
|
||||
|
||||
uninstall:
|
||||
for f in $(TARGETS); do rm -f $(bin_dir)/$$f; done
|
||||
|
||||
adnshost: $(ADH_OBJS) $(DYNAMIC_DEP)
|
||||
$(CC) $(LDFLAGS) $(ADH_OBJS) $(DYNAMIC_LINK) -o $@ $(LDLIBS)
|
||||
|
||||
adnshost_s: $(ADH_OBJS) $(STATIC_LIB)
|
||||
$(CC) $(LDFLAGS) $(ADH_OBJS) $(STATIC_LIB) -o $@ $(LDLIBS)
|
||||
|
||||
$(ADH_OBJS): adnshost.h
|
||||
$(ALL_OBJS): $(ADNSDIR)/adns.h $(ADNSDIR)/config.h
|
||||
adnsresfilter.o: $(ADNSDIR)/tvarith.h
|
||||
|
||||
%: %.o $(DYNAMIC_DEP)
|
||||
$(CC) $(LDFLAGS) $< $(DYNAMIC_LINK) -o $@ $(LDLIBS)
|
||||
|
||||
%_s: %.o $(STATIC_LIB)
|
||||
$(CC) $(LDFLAGS) $< $(STATIC_LIB) -o $@ $(LDLIBS)
|
||||
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* adh-main.c
|
||||
* - useful general-purpose resolver client program
|
||||
* main program and useful subroutines
|
||||
*/
|
||||
/*
|
||||
* This file is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
*
|
||||
* It is part of adns, which is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
* Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef ADNS_JGAA_WIN32
|
||||
# include "adns_win32.h"
|
||||
# include <io.h>
|
||||
#endif
|
||||
|
||||
#include "adnshost.h"
|
||||
|
||||
int rcode;
|
||||
const char *config_text;
|
||||
|
||||
static int used, avail;
|
||||
static char *buf;
|
||||
|
||||
void quitnow(int rc) {
|
||||
if (ads) adns_finish(ads);
|
||||
free(buf);
|
||||
free(ov_id);
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
void sysfail(const char *what, int errnoval) {
|
||||
fprintf(stderr,"adnshost failed: %s: %s\n",what,strerror(errnoval));
|
||||
quitnow(10);
|
||||
}
|
||||
|
||||
void usageerr(const char *fmt, ...) {
|
||||
va_list al;
|
||||
fputs("adnshost usage error: ",stderr);
|
||||
va_start(al,fmt);
|
||||
vfprintf(stderr,fmt,al);
|
||||
va_end(al);
|
||||
putc('\n',stderr);
|
||||
quitnow(11);
|
||||
}
|
||||
|
||||
void outerr(void) {
|
||||
sysfail("write to stdout",errno);
|
||||
}
|
||||
|
||||
void *xmalloc(size_t sz) {
|
||||
void *p;
|
||||
|
||||
p= malloc(sz); if (!p) sysfail("malloc",sz);
|
||||
return p;
|
||||
}
|
||||
|
||||
char *xstrsave(const char *str) {
|
||||
char *p;
|
||||
|
||||
p= xmalloc(strlen(str)+1);
|
||||
strcpy(p,str);
|
||||
return p;
|
||||
}
|
||||
|
||||
void of_config(const struct optioninfo *oi, const char *arg, const char *arg2) {
|
||||
config_text= arg;
|
||||
}
|
||||
|
||||
void of_type(const struct optioninfo *oi, const char *arg, const char *arg2) {
|
||||
static const struct typename {
|
||||
adns_rrtype type;
|
||||
const char *desc;
|
||||
} typenames[]= {
|
||||
/* enhanced versions */
|
||||
{ adns_r_ns, "ns" },
|
||||
{ adns_r_soa, "soa" },
|
||||
{ adns_r_ptr, "ptr" },
|
||||
{ adns_r_mx, "mx" },
|
||||
{ adns_r_rp, "rp" },
|
||||
{ adns_r_addr, "addr" },
|
||||
|
||||
/* types with only one version */
|
||||
{ adns_r_cname, "cname" },
|
||||
{ adns_r_hinfo, "hinfo" },
|
||||
{ adns_r_txt, "txt" },
|
||||
|
||||
/* raw versions */
|
||||
{ adns_r_a, "a" },
|
||||
{ adns_r_ns_raw, "ns-" },
|
||||
{ adns_r_soa_raw, "soa-" },
|
||||
{ adns_r_ptr_raw, "ptr-" },
|
||||
{ adns_r_mx_raw, "mx-" },
|
||||
{ adns_r_rp_raw, "rp-" },
|
||||
|
||||
{ adns_r_none, 0 }
|
||||
};
|
||||
|
||||
const struct typename *tnp;
|
||||
|
||||
for (tnp=typenames;
|
||||
tnp->type && strcmp(arg,tnp->desc);
|
||||
tnp++);
|
||||
if (!tnp->type) usageerr("unknown RR type %s",arg);
|
||||
ov_type= tnp->type;
|
||||
}
|
||||
|
||||
static void process_optarg(const char *arg,
|
||||
const char *const **argv_p,
|
||||
const char *value) {
|
||||
const struct optioninfo *oip;
|
||||
const char *arg2;
|
||||
int invert;
|
||||
|
||||
if (arg[0] == '-' || arg[0] == '+') {
|
||||
if (arg[0] == '-' && arg[1] == '-') {
|
||||
if (!strncmp(arg,"--no-",5)) {
|
||||
invert= 1;
|
||||
oip= opt_findl(arg+5);
|
||||
} else {
|
||||
invert= 0;
|
||||
oip= opt_findl(arg+2);
|
||||
}
|
||||
if (oip->type == ot_funcarg) {
|
||||
arg= argv_p ? *++(*argv_p) : value;
|
||||
if (!arg) usageerr("option --%s requires a value argument",oip->lopt);
|
||||
arg2= 0;
|
||||
} else if (oip->type == ot_funcarg2) {
|
||||
assert(argv_p);
|
||||
arg= *++(*argv_p);
|
||||
arg2= arg ? *++(*argv_p) : 0;
|
||||
if (!arg || !arg2)
|
||||
usageerr("option --%s requires two more arguments", oip->lopt);
|
||||
} else {
|
||||
if (value) usageerr("option --%s does not take a value",oip->lopt);
|
||||
arg= 0;
|
||||
arg2= 0;
|
||||
}
|
||||
opt_do(oip,invert,arg,arg2);
|
||||
} else if (arg[0] == '-' && arg[1] == 0) {
|
||||
arg= argv_p ? *++(*argv_p) : value;
|
||||
if (!arg) usageerr("option `-' must be followed by a domain");
|
||||
query_do(arg);
|
||||
} else { /* arg[1] != '-', != '\0' */
|
||||
invert= (arg[0] == '+');
|
||||
++arg;
|
||||
while (*arg) {
|
||||
oip= opt_finds(&arg);
|
||||
if (oip->type == ot_funcarg) {
|
||||
if (!*arg) {
|
||||
arg= argv_p ? *++(*argv_p) : value;
|
||||
if (!arg) usageerr("option -%s requires a value argument",oip->sopt);
|
||||
} else {
|
||||
if (value) usageerr("two values for option -%s given !",oip->sopt);
|
||||
}
|
||||
opt_do(oip,invert,arg,0);
|
||||
arg= "";
|
||||
} else {
|
||||
if (value) usageerr("option -%s does not take a value",oip->sopt);
|
||||
opt_do(oip,invert,0,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { /* arg[0] != '-' */
|
||||
query_do(arg);
|
||||
}
|
||||
}
|
||||
|
||||
static void read_stdin(void) {
|
||||
int anydone, r;
|
||||
char *newline, *space;
|
||||
|
||||
anydone= 0;
|
||||
while (!anydone || used) {
|
||||
while (!(newline= memchr(buf,'\n',used))) {
|
||||
if (used == avail) {
|
||||
avail += 20; avail <<= 1;
|
||||
buf= realloc(buf,avail);
|
||||
if (!buf) sysfail("realloc stdin buffer",errno);
|
||||
}
|
||||
do {
|
||||
r= read(0,buf+used,avail-used);
|
||||
} while (r < 0 && errno == EINTR);
|
||||
if (r == 0) {
|
||||
if (used) {
|
||||
/* fake up final newline */
|
||||
buf[used++]= '\n';
|
||||
r= 1;
|
||||
} else {
|
||||
ov_pipe= 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (r < 0) sysfail("read stdin",errno);
|
||||
used += r;
|
||||
}
|
||||
*newline++= 0;
|
||||
space= strchr(buf,' ');
|
||||
if (space) *space++= 0;
|
||||
process_optarg(buf,0,space);
|
||||
used -= (newline-buf);
|
||||
memmove(buf,newline,used);
|
||||
anydone= 1;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char *const *argv) {
|
||||
struct timeval *tv, tvbuf;
|
||||
adns_query qu;
|
||||
void *qun_v;
|
||||
adns_answer *answer;
|
||||
int r, maxfd;
|
||||
fd_set readfds, writefds, exceptfds;
|
||||
const char *arg;
|
||||
|
||||
ensure_adns_init();
|
||||
|
||||
while ((arg= *++argv)) process_optarg(arg,&argv,0);
|
||||
|
||||
if (!ov_pipe && !ads) usageerr("no domains given, and -f/--pipe not used; try --help");
|
||||
|
||||
for (;;) {
|
||||
for (;;) {
|
||||
qu= ov_asynch ? 0 : outstanding.head ? outstanding.head->qu : 0;
|
||||
r= adns_check(ads,&qu,&answer,&qun_v);
|
||||
if (r == EAGAIN) break;
|
||||
if (r == ESRCH) { if (!ov_pipe) goto x_quit; else break; }
|
||||
assert(!r);
|
||||
query_done(qun_v,answer);
|
||||
}
|
||||
maxfd= 0;
|
||||
FD_ZERO(&readfds);
|
||||
FD_ZERO(&writefds);
|
||||
FD_ZERO(&exceptfds);
|
||||
if (ov_pipe) {
|
||||
maxfd= 1;
|
||||
FD_SET(0,&readfds);
|
||||
}
|
||||
tv= 0;
|
||||
adns_beforeselect(ads, &maxfd, &readfds,&writefds,&exceptfds, &tv,&tvbuf,0);
|
||||
ADNS_CLEAR_ERRNO;
|
||||
r= select(maxfd, &readfds,&writefds,&exceptfds, tv);
|
||||
ADNS_CAPTURE_ERRNO;
|
||||
if (r == -1) {
|
||||
ADNS_CAPTURE_ERRNO;
|
||||
if (errno == EINTR) continue;
|
||||
sysfail("select",errno);
|
||||
}
|
||||
adns_afterselect(ads, maxfd, &readfds,&writefds,&exceptfds, 0);
|
||||
if (ov_pipe && FD_ISSET(0,&readfds)) read_stdin();
|
||||
}
|
||||
x_quit:
|
||||
if (fclose(stdout)) outerr();
|
||||
quitnow(rcode);
|
||||
}
|
||||
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
* adh-opts.c
|
||||
* - useful general-purpose resolver client program
|
||||
* option handling tables etc.
|
||||
*/
|
||||
/*
|
||||
* This file is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
*
|
||||
* It is part of adns, which is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
* Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef ADNS_JGAA_WIN32
|
||||
# include "adns_win32.h"
|
||||
#endif
|
||||
|
||||
#include "adnshost.h"
|
||||
|
||||
int ov_env=1, ov_pipe=0, ov_asynch=0;
|
||||
int ov_verbose= 0;
|
||||
adns_rrtype ov_type= adns_r_none;
|
||||
int ov_search=0, ov_qc_query=0, ov_qc_anshost=0, ov_qc_cname=1;
|
||||
int ov_tcp=0, ov_cname=0, ov_format=fmt_default;
|
||||
char *ov_id= 0;
|
||||
struct perqueryflags_remember ov_pqfr = { 1,1,1, tm_none };
|
||||
|
||||
static const struct optioninfo global_options[]= {
|
||||
{ ot_desconly, "global binary options:" },
|
||||
{ ot_flag, "Do not look at environment variables at all",
|
||||
"e", "env", &ov_env, 0 },
|
||||
{ ot_flag, "Read queries on stdin instead of using args",
|
||||
"f", "pipe", &ov_pipe, 1 },
|
||||
{ ot_flag, "Allow answers to be reordered",
|
||||
"a", "asynch", &ov_asynch, 1 },
|
||||
|
||||
{ ot_desconly, "answer/error output format and destination (see below):" },
|
||||
{ ot_value, "Answers to stdout, errors as messages to stderr (default)",
|
||||
"Fs", "fmt-simple", &ov_format, fmt_simple },
|
||||
{ ot_value, "Answers and errors both to stdout in parseable format",
|
||||
"Fi", "fmt-inline", &ov_format, fmt_inline },
|
||||
{ ot_value, "Fully-parseable output format (default for --asynch)",
|
||||
"Fa", "fmt-asynch", &ov_format, fmt_asynch },
|
||||
|
||||
{ ot_desconly, "global verbosity level:" },
|
||||
{ ot_value, "Do not print anything to stderr",
|
||||
"Vq", "quiet", &ov_verbose, adns_if_noerrprint },
|
||||
{ ot_value, "Report unexpected kinds of problem only (default)",
|
||||
"Vn", "no-quiet", &ov_verbose, 0 },
|
||||
{ ot_value, "Debugging mode",
|
||||
"Vd", "debug", &ov_verbose, adns_if_debug },
|
||||
|
||||
{ ot_desconly, "other global options:" },
|
||||
{ ot_funcarg, "Configuration to use instead of /etc/resolv.conf",
|
||||
0, "config", 0,0, of_config, "<config-text>" },
|
||||
{ ot_func, "Print version number",
|
||||
0, "version", 0,0, of_version },
|
||||
{ ot_func, "Print usage information",
|
||||
0, "help", 0,0, of_help },
|
||||
|
||||
{ ot_end }
|
||||
};
|
||||
|
||||
static const struct optioninfo perquery_options[]= {
|
||||
{ ot_desconly, "per-query options:" },
|
||||
{ ot_funcarg, "Query type (see below)",
|
||||
"t", "type", 0,0, &of_type, "type" },
|
||||
{ ot_funcarg, "Do reverse query (address -> name lookup)",
|
||||
"i", "ptr", 0,0, &of_ptr, "addr" },
|
||||
{ ot_funcarg2, "Lookup in in-addr-like `zone' (eg MAPS RBL)",
|
||||
0, "reverse", 0,0, &of_reverse, "addr","zone" },
|
||||
|
||||
{ ot_desconly, "per-query binary options:" },
|
||||
{ ot_flag, "Use the search list",
|
||||
"s", "search", &ov_search, 1 },
|
||||
{ ot_flag, "Let query domains contain quote-requiring chars",
|
||||
"Qq", "qc-query", &ov_qc_query, 1 },
|
||||
{ ot_flag, "Let hostnames in answers contain ...",
|
||||
"Qa", "qc-anshost", &ov_qc_anshost, 1 },
|
||||
{ ot_flag, "Prevent CNAME target domains from containing ...",
|
||||
"Qc", "qc-cname", &ov_qc_cname, 0 },
|
||||
{ ot_flag, "Force use of a virtual circuit",
|
||||
"u", "tcp", &ov_tcp, 1 },
|
||||
{ ot_flag, "Do not display owner name in output",
|
||||
"Do", "show-owner", &ov_pqfr.show_owner, 0 },
|
||||
{ ot_flag, "Do not display RR type in output",
|
||||
"Dt", "show-type", &ov_pqfr.show_type, 0 },
|
||||
{ ot_flag, "Do not display CNAME target in output",
|
||||
"Dc", "show-cname", &ov_pqfr.show_cname, 0 },
|
||||
|
||||
{ ot_desconly, "per-query TTL mode (NB TTL is minimum across all info in reply):" },
|
||||
{ ot_value, "Show the TTL as a TTL",
|
||||
"Tt", "ttl-ttl", &ov_pqfr.ttl, tm_rel },
|
||||
{ ot_value, "Show the TTL as a time_t when the data might expire",
|
||||
"Ta", "ttl-abs", &ov_pqfr.ttl, tm_abs },
|
||||
{ ot_value, "Do not show the TTL (default)",
|
||||
"Tn", "no-ttl", &ov_pqfr.ttl, tm_none },
|
||||
|
||||
{ ot_desconly, "per-query CNAME handling mode:" },
|
||||
{ ot_value, "Call it an error if a CNAME is found",
|
||||
"Cf", "cname-reject", &ov_cname, adns_qf_cname_forbid },
|
||||
{ ot_value, "Allow references to CNAMEs in other RRs",
|
||||
"Cl", "cname-loose", &ov_cname, adns_qf_cname_loose },
|
||||
{ ot_value, "CNAME ok for query domain, but not in RRs (default)",
|
||||
"Cs", "cname-ok", &ov_cname, 0 },
|
||||
|
||||
{ ot_desconly, "asynchronous/pipe mode options:" },
|
||||
{ ot_funcarg, "Set <id>, default is decimal sequence starting 0",
|
||||
0, "asynch-id", 0,0, &of_asynch_id, "id" },
|
||||
{ ot_funcarg, "Cancel the query with id <id> (no error if not found)",
|
||||
0, "cancel-id", 0,0, &of_cancel_id, "id" },
|
||||
|
||||
{ ot_end }
|
||||
};
|
||||
|
||||
static void printusage(void) {
|
||||
static const struct optioninfo *const all_optiontables[]= {
|
||||
global_options, perquery_options, 0
|
||||
};
|
||||
|
||||
const struct optioninfo *const *oiap, *oip=0;
|
||||
int maxsopt, maxlopt, l;
|
||||
|
||||
maxsopt= maxlopt= 0;
|
||||
|
||||
for (oiap=all_optiontables; *oiap; oiap++) {
|
||||
for (oip=*oiap; oip->type != ot_end; oip++) {
|
||||
if (oip->type == ot_funcarg) continue;
|
||||
if (oip->sopt) { l= strlen(oip->sopt); if (l>maxsopt) maxsopt= l; }
|
||||
if (oip->lopt) {
|
||||
l= strlen(oip->lopt);
|
||||
if (oip->type == ot_flag && !oip->value) l+= 3;
|
||||
if (l>maxlopt) maxlopt= l;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fputs("usage: adnshost [global-opts] [query-opts] query-domain\n"
|
||||
" [[query-opts] query-domain ...]\n"
|
||||
" adnshost [global-opts] [query-opts] -f|--pipe\n",
|
||||
stdout);
|
||||
|
||||
for (oiap=all_optiontables; *oiap; oiap++) {
|
||||
putchar('\n');
|
||||
for (oip=*oiap; oip->type != ot_end; oip++) {
|
||||
switch (oip->type) {
|
||||
case ot_flag:
|
||||
if (!oip->value) {
|
||||
if (oip->sopt) {
|
||||
printf(" +%-*s --no-%-*s %s\n",
|
||||
maxsopt, oip->sopt,
|
||||
maxlopt-2, oip->lopt,
|
||||
oip->desc);
|
||||
} else {
|
||||
printf(" --no-%-*s %s\n",
|
||||
maxlopt+maxsopt+1, oip->lopt,
|
||||
oip->desc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ot_value: case ot_func: /* fall through */
|
||||
if (oip->sopt) {
|
||||
printf(" -%-*s --%-*s %s\n",
|
||||
maxsopt, oip->sopt,
|
||||
maxlopt+1, oip->lopt,
|
||||
oip->desc);
|
||||
} else {
|
||||
printf(" --%-*s %s\n",
|
||||
maxlopt+maxsopt+3, oip->lopt,
|
||||
oip->desc);
|
||||
}
|
||||
break;
|
||||
case ot_funcarg:
|
||||
if (oip->sopt) {
|
||||
l= (maxlopt + maxsopt - 9 -
|
||||
(strlen(oip->sopt) + strlen(oip->lopt) + 2*strlen(oip->argdesc)));
|
||||
printf(" -%s<%s> / --%s <%s>%*s%s\n",
|
||||
oip->sopt, oip->argdesc, oip->lopt, oip->argdesc,
|
||||
l>2 ? l : 2, "",
|
||||
oip->desc);
|
||||
} else {
|
||||
l= (maxlopt + maxsopt + 1 -
|
||||
(strlen(oip->lopt) + strlen(oip->argdesc)));
|
||||
printf(" --%s <%s>%*s%s\n",
|
||||
oip->lopt, oip->argdesc,
|
||||
l>2 ? l : 2, "",
|
||||
oip->desc);
|
||||
}
|
||||
break;
|
||||
case ot_funcarg2:
|
||||
assert(!oip->sopt);
|
||||
l= (maxlopt + maxsopt - 2 -
|
||||
(strlen(oip->lopt) + strlen(oip->argdesc) + strlen(oip->argdesc2)));
|
||||
printf(" --%s <%s> <%s>%*s%s\n",
|
||||
oip->lopt, oip->argdesc, oip->argdesc2,
|
||||
l>2 ? l : 2, "",
|
||||
oip->desc);
|
||||
break;
|
||||
case ot_desconly:
|
||||
printf("%s\n", oip->desc);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("\nEscaping domains which might start with `-':\n"
|
||||
" - %-*s Next argument is a domain, but more options may follow\n",
|
||||
maxlopt+maxsopt+3, "<domain>");
|
||||
|
||||
fputs("\n"
|
||||
"Query domains should always be quoted according to master file format.\n"
|
||||
"\n"
|
||||
"For binary options, --FOO and --no-FOO are opposites, as are\n"
|
||||
"-X and +X. In each case the default is the one not listed.\n"
|
||||
"Per query options stay set a particular way until they are reset,\n"
|
||||
"whether they appear on the command line or on stdin.\n"
|
||||
"All global options must preceed the first query domain.\n"
|
||||
"\n"
|
||||
"With -f, the input should be lines with either an option, possibly\n"
|
||||
"with a value argument (separated from the option by a space if it's a long\n"
|
||||
"option), or a domain (possibly preceded by a hyphen and a space to\n"
|
||||
"distinguish it from an option).\n"
|
||||
"\n"
|
||||
"Output format is master file format without class or TTL by default:\n"
|
||||
" [<owner>] [<ttl>] [<type>] <data>\n"
|
||||
"or if the <owner> domain refers to a CNAME and --show-cname is on\n"
|
||||
" [<owner>] [<ttl>] CNAME <cname>\n"
|
||||
" [<cname>] [<ttl>] <type> <data>\n"
|
||||
"When a query fails you get an error message to stderr (with --fmt-simple).\n"
|
||||
"Specify --fmt-inline for lines like this (broken here for readability):\n"
|
||||
" ; failed <statustype> <statusnum> <statusabbrev> \\\n"
|
||||
" [<owner>] [<ttl>] [<cname>] \"<status string>\"\n"
|
||||
"If you use --fmt-asynch, which is the default for --asynch,\n"
|
||||
"each answer (success or failure) is preceded by a line\n"
|
||||
" <id> <nrrs> <statustype> <statusnum> <statusabbrev> \\\n"
|
||||
" [<owner>] [<ttl>] [<cname>] \"<status string>\"\n"
|
||||
"where <nrrs> is the number of RRs that follow and <cname> will be `$' or\n"
|
||||
"the CNAME target; the CNAME indirection and error formats above are not used.\n"
|
||||
"\n"
|
||||
"Exit status:\n"
|
||||
" 0 all went well\n"
|
||||
" 1-6 at least one query failed with statustype:\n"
|
||||
" 1 localfail )\n"
|
||||
" 2 remotefail ) temporary errors\n"
|
||||
" 3 tempfail __)_________________\n"
|
||||
" 4 misconfig )\n"
|
||||
" 5 misquery ) permanent errors\n"
|
||||
" 6 permfail )\n"
|
||||
" 10 system trouble\n"
|
||||
" 11 usage problems\n"
|
||||
"\n"
|
||||
"Query types (see adns.h; default is addr):\n"
|
||||
" ns soa ptr mx rp addr - enhanced versions\n"
|
||||
" cname hinfo txt - types with only one version\n"
|
||||
" a ns- soa- ptr- mx- rp- - _raw versions\n"
|
||||
"Default is addr, or ptr for -i/--ptr queries\n",
|
||||
stdout);
|
||||
if (ferror(stdout)) sysfail("write usage message",errno);
|
||||
}
|
||||
|
||||
void of_version(const struct optioninfo *oi, const char *arg, const char *arg2) {
|
||||
VERSION_PRINT_QUIT("adnshost");
|
||||
}
|
||||
|
||||
void of_help(const struct optioninfo *oi, const char *arg, const char *arg2) {
|
||||
printusage();
|
||||
if (fclose(stdout)) sysfail("finish writing output",errno);
|
||||
quitnow(0);
|
||||
}
|
||||
|
||||
typedef int comparer_type(const char **optp, const struct optioninfo *entry);
|
||||
|
||||
static int oc_long(const char **optp, const struct optioninfo *entry) {
|
||||
return entry->lopt && !strcmp(*optp,entry->lopt);
|
||||
}
|
||||
|
||||
static int oc_short(const char **optp, const struct optioninfo *entry) {
|
||||
const char *sopt;
|
||||
int l;
|
||||
|
||||
sopt= entry->sopt;
|
||||
if (!sopt) return 0;
|
||||
l= strlen(sopt);
|
||||
if (memcmp(*optp,sopt,l)) return 0;
|
||||
(*optp) += l;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct optioninfo *find1(const char **optp,
|
||||
const struct optioninfo *table,
|
||||
comparer_type *comparer) {
|
||||
for (;;) {
|
||||
if (table->type == ot_end) return 0;
|
||||
if (comparer(optp,table)) return table;
|
||||
table++;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct optioninfo *find(const char **optp,
|
||||
const char *prefix,
|
||||
comparer_type *comparer) {
|
||||
const struct optioninfo *oip;
|
||||
const char *opt;
|
||||
|
||||
opt= *optp;
|
||||
oip= find1(optp,perquery_options,comparer);
|
||||
if (oip) return oip;
|
||||
oip= find1(optp,global_options,comparer);
|
||||
if (!oip) usageerr("unknown option %s%s",prefix,opt);
|
||||
if (ads) usageerr("global option %s%s specified after query domain(s)",prefix,opt);
|
||||
return oip;
|
||||
}
|
||||
|
||||
const struct optioninfo *opt_findl(const char *opt) { return find(&opt,"--",oc_long); }
|
||||
const struct optioninfo *opt_finds(const char **optp) { return find(optp,"-",oc_short); }
|
||||
|
||||
static void noninvert(const struct optioninfo *oip) NONRETURNING;
|
||||
static void noninvert(const struct optioninfo *oip) {
|
||||
usageerr("option %s%s%s%s%s may not be inverted",
|
||||
oip->sopt ? "-" : "", oip->sopt ? oip->sopt : "",
|
||||
oip->lopt && oip->sopt ? " / " : "",
|
||||
oip->lopt ? "--" : "", oip->lopt ? oip->lopt : "");
|
||||
}
|
||||
|
||||
void opt_do(const struct optioninfo *oip, int invert,
|
||||
const char *arg, const char *arg2) {
|
||||
switch (oip->type) {
|
||||
case ot_flag:
|
||||
assert(!arg);
|
||||
*oip->storep= !invert;
|
||||
return;
|
||||
case ot_value:
|
||||
assert(!arg);
|
||||
if (invert) noninvert(oip);
|
||||
*oip->storep= oip->value;
|
||||
return;
|
||||
case ot_func: case ot_funcarg: case ot_funcarg2:
|
||||
if (invert) noninvert(oip);
|
||||
oip->func(oip,arg,arg2);
|
||||
return;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* adh-query.c
|
||||
* - useful general-purpose resolver client program
|
||||
* make queries and print answers
|
||||
*/
|
||||
/*
|
||||
* This file is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
*
|
||||
* It is part of adns, which is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
* Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef ADNS_JGAA_WIN32
|
||||
# include "adns_win32.h"
|
||||
#endif
|
||||
|
||||
#include "adnshost.h"
|
||||
|
||||
adns_state ads;
|
||||
struct outstanding_list outstanding;
|
||||
|
||||
static unsigned long idcounter;
|
||||
|
||||
void ensure_adns_init(void) {
|
||||
adns_initflags initflags;
|
||||
int r;
|
||||
|
||||
if (ads) return;
|
||||
|
||||
#ifdef SIGPIPE
|
||||
if (signal(SIGPIPE,SIG_IGN) == SIG_ERR) sysfail("ignore SIGPIPE",errno);
|
||||
#endif
|
||||
|
||||
initflags= adns_if_noautosys|adns_if_nosigpipe|ov_verbose;
|
||||
if (!ov_env) initflags |= adns_if_noenv;
|
||||
|
||||
if (config_text) {
|
||||
r= adns_init_strcfg(&ads, initflags, stderr, config_text);
|
||||
} else {
|
||||
r= adns_init(&ads, initflags, 0);
|
||||
}
|
||||
if (r) sysfail("adns_init",r);
|
||||
|
||||
if (ov_format == fmt_default)
|
||||
ov_format= ov_asynch ? fmt_asynch : fmt_simple;
|
||||
}
|
||||
|
||||
static void prep_query(struct query_node **qun_r, int *quflags_r) {
|
||||
struct query_node *qun;
|
||||
char idbuf[20];
|
||||
|
||||
if (ov_pipe && !ads) usageerr("-f/--pipe not consistent with domains on command line");
|
||||
ensure_adns_init();
|
||||
|
||||
qun= malloc(sizeof(*qun));
|
||||
qun->pqfr= ov_pqfr;
|
||||
if (ov_id) {
|
||||
qun->id= xstrsave(ov_id);
|
||||
} else {
|
||||
sprintf(idbuf,"%lu",idcounter++);
|
||||
idcounter &= 0x0fffffffflu;
|
||||
qun->id= xstrsave(idbuf);
|
||||
}
|
||||
|
||||
*quflags_r=
|
||||
(ov_search ? adns_qf_search : 0) |
|
||||
(ov_tcp ? adns_qf_usevc : 0) |
|
||||
((ov_pqfr.show_owner || ov_format == fmt_simple) ? adns_qf_owner : 0) |
|
||||
(ov_qc_query ? adns_qf_quoteok_query : 0) |
|
||||
(ov_qc_anshost ? adns_qf_quoteok_anshost : 0) |
|
||||
(ov_qc_cname ? 0 : adns_qf_quoteok_cname) |
|
||||
ov_cname,
|
||||
|
||||
*qun_r= qun;
|
||||
}
|
||||
|
||||
void of_ptr(const struct optioninfo *oi, const char *arg, const char *arg2) {
|
||||
struct query_node *qun;
|
||||
int quflags, r;
|
||||
struct sockaddr_in sa;
|
||||
|
||||
memset(&sa,0,sizeof(sa));
|
||||
sa.sin_family= AF_INET;
|
||||
if (!inet_aton(arg,&sa.sin_addr)) usageerr("invalid IP address %s",arg);
|
||||
|
||||
prep_query(&qun,&quflags);
|
||||
qun->owner= xstrsave(arg);
|
||||
r= adns_submit_reverse(ads,
|
||||
(struct sockaddr*)&sa,
|
||||
ov_type == adns_r_none ? adns_r_ptr : ov_type,
|
||||
quflags,
|
||||
qun,
|
||||
&qun->qu);
|
||||
if (r) sysfail("adns_submit_reverse",r);
|
||||
|
||||
LIST_LINK_TAIL(outstanding,qun);
|
||||
}
|
||||
|
||||
void of_reverse(const struct optioninfo *oi, const char *arg, const char *arg2) {
|
||||
struct query_node *qun;
|
||||
int quflags, r;
|
||||
struct sockaddr_in sa;
|
||||
|
||||
memset(&sa,0,sizeof(sa));
|
||||
sa.sin_family= AF_INET;
|
||||
if (!inet_aton(arg,&sa.sin_addr)) usageerr("invalid IP address %s",arg);
|
||||
|
||||
prep_query(&qun,&quflags);
|
||||
qun->owner= xmalloc(strlen(arg) + strlen(arg2) + 2);
|
||||
sprintf(qun->owner, "%s %s", arg,arg2);
|
||||
r= adns_submit_reverse_any(ads,
|
||||
(struct sockaddr*)&sa, arg2,
|
||||
ov_type == adns_r_none ? adns_r_txt : ov_type,
|
||||
quflags,
|
||||
qun,
|
||||
&qun->qu);
|
||||
if (r) sysfail("adns_submit_reverse",r);
|
||||
|
||||
LIST_LINK_TAIL(outstanding,qun);
|
||||
}
|
||||
|
||||
void query_do(const char *domain) {
|
||||
struct query_node *qun;
|
||||
int quflags, r;
|
||||
|
||||
prep_query(&qun,&quflags);
|
||||
qun->owner= xstrsave(domain);
|
||||
r= adns_submit(ads, domain,
|
||||
ov_type == adns_r_none ? adns_r_addr : ov_type,
|
||||
quflags,
|
||||
qun,
|
||||
&qun->qu);
|
||||
if (r) sysfail("adns_submit",r);
|
||||
|
||||
LIST_LINK_TAIL(outstanding,qun);
|
||||
}
|
||||
|
||||
static void dequeue_query(struct query_node *qun) {
|
||||
LIST_UNLINK(outstanding,qun);
|
||||
free(qun->id);
|
||||
free(qun->owner);
|
||||
free(qun);
|
||||
}
|
||||
|
||||
static void print_withspace(const char *str) {
|
||||
if (printf("%s ", str) == EOF) outerr();
|
||||
}
|
||||
|
||||
static void print_ttl(struct query_node *qun, adns_answer *answer) {
|
||||
unsigned long ttl;
|
||||
time_t now;
|
||||
|
||||
switch (qun->pqfr.ttl) {
|
||||
case tm_none:
|
||||
return;
|
||||
case tm_rel:
|
||||
if (time(&now) == (time_t)-1) sysfail("get current time",errno);
|
||||
ttl= answer->expires < now ? 0 : answer->expires - now;
|
||||
break;
|
||||
case tm_abs:
|
||||
ttl= answer->expires;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
if (printf("%lu ",ttl) == EOF) outerr();
|
||||
}
|
||||
|
||||
static const char *owner_show(struct query_node *qun, adns_answer *answer) {
|
||||
return answer->owner ? answer->owner : qun->owner;
|
||||
}
|
||||
|
||||
static void print_owner_ttl(struct query_node *qun, adns_answer *answer) {
|
||||
if (qun->pqfr.show_owner) print_withspace(owner_show(qun,answer));
|
||||
print_ttl(qun,answer);
|
||||
}
|
||||
|
||||
static void check_status(adns_status st) {
|
||||
static const adns_status statuspoints[]= {
|
||||
adns_s_ok,
|
||||
adns_s_max_localfail, adns_s_max_remotefail, adns_s_max_tempfail,
|
||||
adns_s_max_misconfig, adns_s_max_misquery
|
||||
};
|
||||
|
||||
const adns_status *spp;
|
||||
int minrcode;
|
||||
|
||||
for (minrcode=0, spp=statuspoints;
|
||||
spp < statuspoints + (sizeof(statuspoints)/sizeof(statuspoints[0]));
|
||||
spp++)
|
||||
if (st > *spp) minrcode++;
|
||||
if (rcode < minrcode) rcode= minrcode;
|
||||
}
|
||||
|
||||
static void print_status(adns_status st, struct query_node *qun, adns_answer *answer) {
|
||||
const char *statustypeabbrev, *statusabbrev, *statusstring;
|
||||
|
||||
statustypeabbrev= adns_errtypeabbrev(st);
|
||||
statusabbrev= adns_errabbrev(st);
|
||||
statusstring= adns_strerror(st);
|
||||
assert(!strchr(statusstring,'"'));
|
||||
|
||||
if (printf("%s %d %s ", statustypeabbrev, st, statusabbrev)
|
||||
== EOF) outerr();
|
||||
print_owner_ttl(qun,answer);
|
||||
if (qun->pqfr.show_cname)
|
||||
print_withspace(answer->cname ? answer->cname : "$");
|
||||
if (printf("\"%s\"\n", statusstring) == EOF) outerr();
|
||||
}
|
||||
|
||||
static void print_dnsfail(adns_status st, struct query_node *qun, adns_answer *answer) {
|
||||
int r;
|
||||
const char *typename, *statusstring;
|
||||
adns_status ist;
|
||||
|
||||
if (ov_format == fmt_inline) {
|
||||
if (fputs("; failed ",stdout) == EOF) outerr();
|
||||
print_status(st,qun,answer);
|
||||
return;
|
||||
}
|
||||
assert(ov_format == fmt_simple);
|
||||
if (st == adns_s_nxdomain) {
|
||||
r= fprintf(stderr,"%s does not exist\n", owner_show(qun,answer));
|
||||
} else {
|
||||
ist= adns_rr_info(answer->type, &typename, 0,0,0,0);
|
||||
if (st == adns_s_nodata) {
|
||||
r= fprintf(stderr,"%s has no %s record\n", owner_show(qun,answer), typename);
|
||||
} else {
|
||||
statusstring= adns_strerror(st);
|
||||
r= fprintf(stderr,"Error during DNS %s lookup for %s: %s\n",
|
||||
typename, owner_show(qun,answer), statusstring);
|
||||
}
|
||||
}
|
||||
if (r == EOF) sysfail("write error message to stderr",errno);
|
||||
}
|
||||
|
||||
void query_done(struct query_node *qun, adns_answer *answer) {
|
||||
adns_status st, ist;
|
||||
int rrn, nrrs;
|
||||
const char *rrp, *realowner, *typename;
|
||||
char *datastr;
|
||||
|
||||
st= answer->status;
|
||||
nrrs= answer->nrrs;
|
||||
if (ov_format == fmt_asynch) {
|
||||
check_status(st);
|
||||
if (printf("%s %d ", qun->id, nrrs) == EOF) outerr();
|
||||
print_status(st,qun,answer);
|
||||
} else {
|
||||
if (qun->pqfr.show_cname && answer->cname) {
|
||||
print_owner_ttl(qun,answer);
|
||||
if (qun->pqfr.show_type) print_withspace("CNAME");
|
||||
if (printf("%s\n", answer->cname) == EOF) outerr();
|
||||
}
|
||||
if (st) {
|
||||
check_status(st);
|
||||
print_dnsfail(st,qun,answer);
|
||||
}
|
||||
}
|
||||
if (qun->pqfr.show_owner) {
|
||||
realowner= answer->cname ? answer->cname : owner_show(qun,answer);
|
||||
assert(realowner);
|
||||
} else {
|
||||
realowner= 0;
|
||||
}
|
||||
if (nrrs) {
|
||||
for (rrn=0, rrp = answer->rrs.untyped;
|
||||
rrn < nrrs;
|
||||
rrn++, rrp += answer->rrsz) {
|
||||
if (realowner) print_withspace(realowner);
|
||||
print_ttl(qun,answer);
|
||||
ist= adns_rr_info(answer->type, &typename, 0, 0, rrp, &datastr);
|
||||
if (ist == adns_s_nomemory) sysfail("adns_rr_info failed",ENOMEM);
|
||||
assert(!ist);
|
||||
if (qun->pqfr.show_type) print_withspace(typename);
|
||||
if (printf("%s\n",datastr) == EOF) outerr();
|
||||
free(datastr);
|
||||
}
|
||||
}
|
||||
if (fflush(stdout)) outerr();
|
||||
free(answer);
|
||||
dequeue_query(qun);
|
||||
}
|
||||
|
||||
void of_asynch_id(const struct optioninfo *oi, const char *arg, const char *arg2) {
|
||||
free(ov_id);
|
||||
ov_id= xstrsave(arg);
|
||||
}
|
||||
|
||||
void of_cancel_id(const struct optioninfo *oi, const char *arg, const char *arg2) {
|
||||
struct query_node *qun;
|
||||
|
||||
for (qun= outstanding.head;
|
||||
qun && strcmp(qun->id,arg);
|
||||
qun= qun->next);
|
||||
if (!qun) return;
|
||||
adns_cancel(qun->qu);
|
||||
dequeue_query(qun);
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* adnshost.h
|
||||
* - useful general-purpose resolver client program, header file
|
||||
*/
|
||||
/*
|
||||
* This file is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
*
|
||||
* It is part of adns, which is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
* Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef ADNSHOST_H_INCLUDED
|
||||
#define ADNSHOST_H_INCLUDED
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifndef ADNS_JGAA_WIN32
|
||||
# include <sys/types.h>
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "adns.h"
|
||||
#include "dlist.h"
|
||||
#include "client.h"
|
||||
|
||||
#ifdef ADNS_REGRESS_TEST
|
||||
# include "hredirect.h"
|
||||
#endif
|
||||
|
||||
/* declarations related to option processing */
|
||||
|
||||
struct optioninfo;
|
||||
typedef void optfunc(const struct optioninfo *oi, const char *arg, const char *arg2);
|
||||
|
||||
struct optioninfo {
|
||||
enum oi_type {
|
||||
ot_end, ot_desconly,
|
||||
ot_flag, ot_value, ot_func, ot_funcarg, ot_funcarg2
|
||||
} type;
|
||||
const char *desc;
|
||||
const char *sopt, *lopt;
|
||||
int *storep, value;
|
||||
optfunc *func;
|
||||
const char *argdesc, *argdesc2;
|
||||
};
|
||||
|
||||
enum ttlmode { tm_none, tm_rel, tm_abs };
|
||||
enum outputformat { fmt_default, fmt_simple, fmt_inline, fmt_asynch };
|
||||
|
||||
struct perqueryflags_remember {
|
||||
int show_owner, show_type, show_cname;
|
||||
int ttl;
|
||||
};
|
||||
|
||||
extern int ov_env, ov_pipe, ov_asynch;
|
||||
extern int ov_verbose;
|
||||
extern adns_rrtype ov_type;
|
||||
extern int ov_search, ov_qc_query, ov_qc_anshost, ov_qc_cname;
|
||||
extern int ov_tcp, ov_cname, ov_format;
|
||||
extern char *ov_id;
|
||||
extern struct perqueryflags_remember ov_pqfr;
|
||||
|
||||
extern optfunc of_config, of_version, of_help, of_type, of_ptr, of_reverse;
|
||||
extern optfunc of_asynch_id, of_cancel_id;
|
||||
|
||||
const struct optioninfo *opt_findl(const char *opt);
|
||||
const struct optioninfo *opt_finds(const char **optp);
|
||||
void opt_do(const struct optioninfo *oip, int invert, const char *arg, const char *arg2);
|
||||
|
||||
/* declarations related to query processing */
|
||||
|
||||
struct query_node {
|
||||
struct query_node *next, *back;
|
||||
struct perqueryflags_remember pqfr;
|
||||
char *id, *owner;
|
||||
adns_query qu;
|
||||
};
|
||||
|
||||
extern adns_state ads;
|
||||
extern struct outstanding_list { struct query_node *head, *tail; } outstanding;
|
||||
|
||||
void ensure_adns_init(void);
|
||||
void query_do(const char *domain);
|
||||
void query_done(struct query_node *qun, adns_answer *answer);
|
||||
|
||||
/* declarations related to main program and useful utility functions */
|
||||
|
||||
void sysfail(const char *what, int errnoval) NONRETURNING;
|
||||
void usageerr(const char *what, ...) NONRETURNPRINTFFORMAT(1,2);
|
||||
void outerr(void) NONRETURNING;
|
||||
|
||||
void *xmalloc(size_t sz);
|
||||
char *xstrsave(const char *str);
|
||||
|
||||
extern int rcode;
|
||||
extern const char *config_text; /* 0 => use defaults */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* adnslogres.c
|
||||
* - a replacement for the Apache logresolve program using adns
|
||||
*/
|
||||
/*
|
||||
* This file is
|
||||
* Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
* Copyright (C) 1999-2000 Ian Jackson <[email protected]>
|
||||
*
|
||||
* It is part of adns, which is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
* Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* This version was originally supplied by Tony Finch, but has been
|
||||
* modified by Ian Jackson as it was incorporated into adns and
|
||||
* subsequently.
|
||||
*/
|
||||
|
||||
static const char * const cvsid =
|
||||
"$Id: adnslogres.c,v 1.1 2003/12/18 10:48:20 arty Exp $";
|
||||
|
||||
#ifdef ADNS_JGAA_WIN32
|
||||
# include "adns_win32.h"
|
||||
# include "getopt.h"
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
# include <sys/time.h>
|
||||
# include <unistd.h>
|
||||
# include <string.h>
|
||||
# include <stdlib.h>
|
||||
# include <stdio.h>
|
||||
# include <ctype.h>
|
||||
# include <errno.h>
|
||||
# include <stdarg.h>
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "adns.h"
|
||||
#include "client.h"
|
||||
|
||||
#ifdef ADNS_REGRESS_TEST
|
||||
# include "hredirect.h"
|
||||
#endif
|
||||
|
||||
/* maximum number of concurrent DNS queries */
|
||||
#define MAXMAXPENDING 64000
|
||||
#define DEFMAXPENDING 2000
|
||||
|
||||
/* maximum length of a line */
|
||||
#define MAXLINE 1024
|
||||
|
||||
/* option flags */
|
||||
#define OPT_DEBUG 1
|
||||
|
||||
#ifdef HAVE_POLL
|
||||
# define OPT_POLL 2
|
||||
#endif
|
||||
|
||||
static const char *const progname= "adnslogres";
|
||||
static const char *config_text;
|
||||
|
||||
#define guard_null(str) ((str) ? (str) : "")
|
||||
|
||||
#define sensible_ctype(type,ch) (type((unsigned char)(ch)))
|
||||
/* isfoo() functions from ctype.h can't safely be fed char - blech ! */
|
||||
|
||||
static void msg(const char *fmt, ...) {
|
||||
va_list al;
|
||||
|
||||
fprintf(stderr, "%s: ", progname);
|
||||
va_start(al,fmt);
|
||||
vfprintf(stderr, fmt, al);
|
||||
va_end(al);
|
||||
fputc('\n',stderr);
|
||||
}
|
||||
|
||||
static void aargh(const char *cause) {
|
||||
const char *why = strerror(errno);
|
||||
if (!why) why = "Unknown error";
|
||||
msg("%s: %s (%d)", cause, why, errno);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the IP address and convert to a reverse domain name.
|
||||
*/
|
||||
static char *ipaddr2domain(char *start, char **addr, char **rest) {
|
||||
static char buf[30]; /* "123.123.123.123.in-addr.arpa.\0" */
|
||||
char *ptrs[5];
|
||||
int i;
|
||||
|
||||
ptrs[0]= start;
|
||||
retry:
|
||||
while (!sensible_ctype(isdigit,*ptrs[0]))
|
||||
if (!*ptrs[0]++) {
|
||||
strcpy(buf, "invalid.");
|
||||
*addr= *rest= NULL;
|
||||
return buf;
|
||||
}
|
||||
for (i= 1; i < 5; i++) {
|
||||
ptrs[i]= ptrs[i-1];
|
||||
while (sensible_ctype(isdigit,*ptrs[i]++));
|
||||
if ((i == 4 && !sensible_ctype(isspace,ptrs[i][-1])) ||
|
||||
(i != 4 && ptrs[i][-1] != '.') ||
|
||||
(ptrs[i]-ptrs[i-1] > 4)) {
|
||||
ptrs[0]= ptrs[i]-1;
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
sprintf(buf, "%.*s.%.*s.%.*s.%.*s.in-addr.arpa.",
|
||||
ptrs[4]-ptrs[3]-1, ptrs[3],
|
||||
ptrs[3]-ptrs[2]-1, ptrs[2],
|
||||
ptrs[2]-ptrs[1]-1, ptrs[1],
|
||||
ptrs[1]-ptrs[0]-1, ptrs[0]);
|
||||
*addr= ptrs[0];
|
||||
*rest= ptrs[4]-1;
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void printline(FILE *outf, char *start, char *addr, char *rest, char *domain) {
|
||||
if (domain)
|
||||
fprintf(outf, "%.*s%s%s", addr - start, start, domain, rest);
|
||||
else
|
||||
fputs(start, outf);
|
||||
if (ferror(outf)) aargh("write output");
|
||||
}
|
||||
|
||||
typedef struct logline {
|
||||
struct logline *next;
|
||||
char *start, *addr, *rest;
|
||||
adns_query query;
|
||||
} logline;
|
||||
|
||||
static logline *readline(FILE *inf, adns_state adns, int opts) {
|
||||
static char buf[MAXLINE];
|
||||
char *str;
|
||||
logline *line;
|
||||
|
||||
if (fgets(buf, MAXLINE, inf)) {
|
||||
str= malloc(sizeof(*line) + strlen(buf) + 1);
|
||||
if (!str) aargh("malloc");
|
||||
line= (logline*)str;
|
||||
line->next= NULL;
|
||||
line->start= str+sizeof(logline);
|
||||
strcpy(line->start, buf);
|
||||
str= ipaddr2domain(line->start, &line->addr, &line->rest);
|
||||
if (opts & OPT_DEBUG)
|
||||
msg("submitting %.*s -> %s", line->rest-line->addr, guard_null(line->addr), str);
|
||||
if (adns_submit(adns, str, adns_r_ptr,
|
||||
adns_qf_quoteok_cname|adns_qf_cname_loose,
|
||||
NULL, &line->query))
|
||||
aargh("adns_submit");
|
||||
return line;
|
||||
}
|
||||
if (!feof(inf))
|
||||
aargh("fgets");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void proclog(FILE *inf, FILE *outf, int maxpending, int opts) {
|
||||
int eof, err, len;
|
||||
adns_state adns;
|
||||
adns_answer *answer;
|
||||
logline *head, *tail, *line;
|
||||
adns_initflags initflags;
|
||||
|
||||
initflags= (opts & OPT_DEBUG) ? adns_if_debug : 0;
|
||||
if (config_text) {
|
||||
errno= adns_init_strcfg(&adns, initflags, stderr, config_text);
|
||||
} else {
|
||||
errno= adns_init(&adns, initflags, 0);
|
||||
}
|
||||
if (errno) aargh("adns_init");
|
||||
head= tail= readline(inf, adns, opts);
|
||||
len= 1; eof= 0;
|
||||
while (head) {
|
||||
while (head) {
|
||||
if (opts & OPT_DEBUG)
|
||||
msg("%d in queue; checking %.*s", len,
|
||||
head->rest-head->addr, guard_null(head->addr));
|
||||
if (eof || len >= maxpending) {
|
||||
#ifdef HAVE_POLL
|
||||
if (opts & OPT_POLL)
|
||||
err= adns_wait_poll(adns, &head->query, &answer, NULL);
|
||||
else
|
||||
#endif
|
||||
err= adns_wait(adns, &head->query, &answer, NULL);
|
||||
} else {
|
||||
err= adns_check(adns, &head->query, &answer, NULL);
|
||||
}
|
||||
if (err == EAGAIN) break;
|
||||
if (err) {
|
||||
fprintf(stderr, "%s: adns_wait/check: %s", progname, strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
printline(outf, head->start, head->addr, head->rest,
|
||||
answer->status == adns_s_ok ? *answer->rrs.str : NULL);
|
||||
line= head; head= head->next;
|
||||
free(line);
|
||||
free(answer);
|
||||
len--;
|
||||
}
|
||||
if (!eof) {
|
||||
line= readline(inf, adns, opts);
|
||||
if (line) {
|
||||
if (!head) head= line;
|
||||
else tail->next= line;
|
||||
tail= line; len++;
|
||||
} else {
|
||||
eof= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
adns_finish(adns);
|
||||
}
|
||||
|
||||
static void printhelp(FILE *file) {
|
||||
fputs("usage: adnslogres [<options>] [<logfile>]\n"
|
||||
" adnslogres --version|--help\n"
|
||||
"options: -c <concurrency> set max number of outstanding queries\n"
|
||||
#ifdef HAVE_POLL
|
||||
" -p use poll(2) instead of select(2)\n"
|
||||
#endif
|
||||
" -d turn on debugging\n"
|
||||
" -C <config> use instead of contents of resolv.conf\n",
|
||||
stdout);
|
||||
}
|
||||
|
||||
static void usage(void) {
|
||||
printhelp(stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int c, opts, maxpending;
|
||||
extern char *optarg;
|
||||
FILE *inf;
|
||||
|
||||
if (argv[1] && !strncmp(argv[1],"--",2)) {
|
||||
if (!strcmp(argv[1],"--help")) {
|
||||
printhelp(stdout);
|
||||
} else if (!strcmp(argv[1],"--version")) {
|
||||
fputs(VERSION_MESSAGE("adnslogres"),stdout);
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
if (ferror(stdout) || fclose(stdout)) { perror("stdout"); exit(1); }
|
||||
exit(0);
|
||||
}
|
||||
|
||||
maxpending= DEFMAXPENDING;
|
||||
opts= 0;
|
||||
while ((c= getopt(argc, argv, "c:C:dp")) != -1)
|
||||
switch (c) {
|
||||
case 'c':
|
||||
maxpending= atoi(optarg);
|
||||
if (maxpending < 1 || maxpending > MAXMAXPENDING) {
|
||||
fprintf(stderr, "%s: unfeasible concurrency %d\n", progname, maxpending);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'C':
|
||||
config_text= optarg;
|
||||
break;
|
||||
case 'd':
|
||||
opts|= OPT_DEBUG;
|
||||
break;
|
||||
#ifdef HAVE_POLL
|
||||
case 'p':
|
||||
opts|= OPT_POLL;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
|
||||
argc-= optind;
|
||||
argv+= optind;
|
||||
|
||||
inf= NULL;
|
||||
if (argc == 0)
|
||||
inf= stdin;
|
||||
else if (argc == 1)
|
||||
inf= fopen(*argv, "r");
|
||||
else
|
||||
usage();
|
||||
|
||||
if (!inf)
|
||||
aargh("couldn't open input");
|
||||
|
||||
proclog(inf, stdout, maxpending, opts);
|
||||
|
||||
if (fclose(inf))
|
||||
aargh("fclose input");
|
||||
if (fclose(stdout))
|
||||
aargh("fclose output");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,477 @@
|
||||
/*
|
||||
* adnsresfilter.c
|
||||
* - filter which does resolving, not part of the library
|
||||
*/
|
||||
/*
|
||||
* This file is
|
||||
* Copyright (C) 1999-2000 Ian Jackson <[email protected]>
|
||||
*
|
||||
* It is part of adns, which is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
* Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <search.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "adns.h"
|
||||
#include "dlist.h"
|
||||
#include "tvarith.h"
|
||||
#include "client.h"
|
||||
|
||||
#ifdef ADNS_REGRESS_TEST
|
||||
# include "hredirect.h"
|
||||
#endif
|
||||
|
||||
struct outqueuenode {
|
||||
struct outqueuenode *next, *back;
|
||||
void *buffer;
|
||||
char *textp;
|
||||
int textlen;
|
||||
struct timeval printbefore;
|
||||
struct treething *addr;
|
||||
};
|
||||
|
||||
static int bracket, forever, address;
|
||||
static unsigned long timeout= 1000;
|
||||
static adns_rrtype rrt= adns_r_ptr;
|
||||
static adns_initflags initflags= 0;
|
||||
static const char *config_text;
|
||||
|
||||
static int outblocked, inputeof;
|
||||
static struct { struct outqueuenode *head, *tail; } outqueue;
|
||||
static int peroutqueuenode, outqueuelen;
|
||||
|
||||
static struct sockaddr_in sa;
|
||||
static adns_state ads;
|
||||
|
||||
static char addrtextbuf[14];
|
||||
static int cbyte, inbyte, inbuf;
|
||||
static unsigned char bytes[4];
|
||||
static struct timeval printbefore;
|
||||
|
||||
struct treething {
|
||||
unsigned char bytes[4];
|
||||
adns_query qu;
|
||||
adns_answer *ans;
|
||||
};
|
||||
|
||||
static struct treething *newthing;
|
||||
static void *treeroot;
|
||||
|
||||
static int nonblock(int fd, int isnonblock) {
|
||||
int r;
|
||||
|
||||
r= fcntl(fd,F_GETFL);
|
||||
if (r==-1) return -1;
|
||||
r= fcntl(fd,F_SETFL, isnonblock ? r|O_NONBLOCK : r&~O_NONBLOCK);
|
||||
if (r==-1) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void quitnow(int exitstatus) {
|
||||
nonblock(0,0);
|
||||
nonblock(1,0);
|
||||
exit(exitstatus);
|
||||
}
|
||||
|
||||
static void sysfail(const char *what) NONRETURNING;
|
||||
static void sysfail(const char *what) {
|
||||
fprintf(stderr,"adnsresfilter: system call failed: %s: %s\n",what,strerror(errno));
|
||||
quitnow(2);
|
||||
}
|
||||
|
||||
static void *xmalloc(size_t sz) {
|
||||
void *r;
|
||||
r= malloc(sz); if (r) return r;
|
||||
sysfail("malloc");
|
||||
}
|
||||
|
||||
static void outputerr(void) NONRETURNING;
|
||||
static void outputerr(void) { sysfail("write to stdout"); }
|
||||
|
||||
static void usage(void) {
|
||||
if (printf("usage: adnsresfilter [<options ...>]\n"
|
||||
" adnsresfilter -h|--help | --version\n"
|
||||
"options: -t<milliseconds>|--timeout <milliseconds>\n"
|
||||
" -w|--wait (always wait for queries to time out or fail)\n"
|
||||
" -b|--brackets (require [...] around IP addresses)\n"
|
||||
" -a|--address (always include [address] in output)\n"
|
||||
" -u|--unchecked (do not forward map for checking)\n"
|
||||
" --config <text> (use this instead of resolv.conf)\n"
|
||||
" --debug (turn on adns resolver debugging)\n"
|
||||
"Timeout is the maximum amount to delay any particular bit of output for.\n"
|
||||
"Lookups will go on in the background. Default timeout = 1000 (ms).\n")
|
||||
== EOF) outputerr();
|
||||
if (fflush(stdout)) sysfail("flush stdout");
|
||||
}
|
||||
|
||||
static void usageerr(const char *why) NONRETURNING;
|
||||
static void usageerr(const char *why) {
|
||||
fprintf(stderr,"adnsresfilter: bad usage: %s\n",why);
|
||||
usage();
|
||||
quitnow(1);
|
||||
}
|
||||
|
||||
static void adnsfail(const char *what, int e) NONRETURNING;
|
||||
static void adnsfail(const char *what, int e) {
|
||||
fprintf(stderr,"adnsresfilter: adns call failed: %s: %s\n",what,strerror(e));
|
||||
quitnow(2);
|
||||
}
|
||||
|
||||
static void settimeout(const char *arg) {
|
||||
char *ep;
|
||||
timeout= strtoul(arg,&ep,0);
|
||||
if (*ep) usageerr("invalid timeout");
|
||||
}
|
||||
|
||||
static void parseargs(const char *const *argv) {
|
||||
const char *arg;
|
||||
int c;
|
||||
|
||||
while ((arg= *++argv)) {
|
||||
if (arg[0] != '-') usageerr("no non-option arguments are allowed");
|
||||
if (arg[1] == '-') {
|
||||
if (!strcmp(arg,"--timeout")) {
|
||||
if (!(arg= *++argv)) usageerr("--timeout needs a value");
|
||||
settimeout(arg);
|
||||
forever= 0;
|
||||
} else if (!strcmp(arg,"--wait")) {
|
||||
forever= 1;
|
||||
} else if (!strcmp(arg,"--brackets")) {
|
||||
bracket= 1;
|
||||
} else if (!strcmp(arg,"--address")) {
|
||||
address= 1;
|
||||
} else if (!strcmp(arg,"--unchecked")) {
|
||||
rrt= adns_r_ptr_raw;
|
||||
} else if (!strcmp(arg,"--config")) {
|
||||
if (!(arg= *++argv)) usageerr("--config needs a value");
|
||||
config_text= arg;
|
||||
} else if (!strcmp(arg,"--debug")) {
|
||||
initflags |= adns_if_debug;
|
||||
} else if (!strcmp(arg,"--help")) {
|
||||
usage(); quitnow(0);
|
||||
} else if (!strcmp(arg,"--version")) {
|
||||
VERSION_PRINT_QUIT("adnsresfilter"); quitnow(0);
|
||||
} else {
|
||||
usageerr("unknown long option");
|
||||
}
|
||||
} else {
|
||||
while ((c= *++arg)) {
|
||||
switch (c) {
|
||||
case 't':
|
||||
if (*++arg) settimeout(arg);
|
||||
else if ((arg= *++argv)) settimeout(arg);
|
||||
else usageerr("-t needs a value");
|
||||
forever= 0;
|
||||
arg= "\0";
|
||||
break;
|
||||
case 'w':
|
||||
forever= 1;
|
||||
break;
|
||||
case 'b':
|
||||
bracket= 1;
|
||||
break;
|
||||
case 'a':
|
||||
address= 1;
|
||||
break;
|
||||
case 'u':
|
||||
rrt= adns_r_ptr_raw;
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
quitnow(0);
|
||||
default:
|
||||
usageerr("unknown short option");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void queueoutchar(int c) {
|
||||
struct outqueuenode *entry;
|
||||
|
||||
entry= outqueue.tail;
|
||||
if (!entry || entry->addr || entry->textlen >= peroutqueuenode) {
|
||||
peroutqueuenode= !peroutqueuenode || !entry || entry->addr ? 128 :
|
||||
peroutqueuenode >= 1024 ? 4096 : peroutqueuenode<<2;
|
||||
entry= xmalloc(sizeof(*entry));
|
||||
entry->buffer= xmalloc(peroutqueuenode);
|
||||
entry->textp= entry->buffer;
|
||||
entry->textlen= 0;
|
||||
entry->addr= 0;
|
||||
LIST_LINK_TAIL(outqueue,entry);
|
||||
outqueuelen++;
|
||||
}
|
||||
entry->textp[entry->textlen++]= c;
|
||||
}
|
||||
|
||||
static void queueoutstr(const char *str, int len) {
|
||||
while (len-- > 0) queueoutchar(*str++);
|
||||
}
|
||||
|
||||
static void writestdout(struct outqueuenode *entry) {
|
||||
int r;
|
||||
|
||||
while (entry->textlen) {
|
||||
r= write(1, entry->textp, entry->textlen);
|
||||
if (r < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
if (errno == EAGAIN) { outblocked= 1; break; }
|
||||
sysfail("write stdout");
|
||||
}
|
||||
assert(r <= entry->textlen);
|
||||
entry->textp += r;
|
||||
entry->textlen -= r;
|
||||
}
|
||||
if (!entry->textlen) {
|
||||
LIST_UNLINK(outqueue,entry);
|
||||
free(entry->buffer);
|
||||
free(entry);
|
||||
outqueuelen--;
|
||||
}
|
||||
}
|
||||
|
||||
static void replacetextwithname(struct outqueuenode *entry) {
|
||||
char *name, *newbuf;
|
||||
int namelen, newlen;
|
||||
|
||||
name= entry->addr->ans->rrs.str[0];
|
||||
namelen= strlen(name);
|
||||
if (!address) {
|
||||
free(entry->buffer);
|
||||
entry->buffer= 0;
|
||||
entry->textp= name;
|
||||
entry->textlen= namelen;
|
||||
} else {
|
||||
newlen= entry->textlen + namelen + (bracket ? 0 : 2);
|
||||
newbuf= xmalloc(newlen + 1);
|
||||
sprintf(newbuf, bracket ? "%s%.*s" : "%s[%.*s]", name, entry->textlen, entry->textp);
|
||||
free(entry->buffer);
|
||||
entry->buffer= entry->textp= newbuf;
|
||||
entry->textlen= newlen;
|
||||
}
|
||||
}
|
||||
|
||||
static void checkadnsqueries(void) {
|
||||
adns_query qu;
|
||||
adns_answer *ans;
|
||||
void *context;
|
||||
struct treething *foundthing;
|
||||
int r;
|
||||
|
||||
for (;;) {
|
||||
qu= 0; context= 0; ans= 0;
|
||||
r= adns_check(ads,&qu,&ans,&context);
|
||||
if (r == ESRCH || r == EAGAIN) break;
|
||||
assert(!r);
|
||||
foundthing= context;
|
||||
foundthing->ans= ans;
|
||||
foundthing->qu= 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void restartbuf(void) {
|
||||
if (inbuf>0) queueoutstr(addrtextbuf,inbuf);
|
||||
inbuf= 0;
|
||||
}
|
||||
|
||||
static int comparer(const void *a, const void *b) {
|
||||
return memcmp(a,b,4);
|
||||
}
|
||||
|
||||
static void procaddr(void) {
|
||||
struct treething *foundthing;
|
||||
void **searchfound;
|
||||
struct outqueuenode *entry;
|
||||
int r;
|
||||
|
||||
if (!newthing) {
|
||||
newthing= xmalloc(sizeof(struct treething));
|
||||
newthing->qu= 0;
|
||||
newthing->ans= 0;
|
||||
}
|
||||
|
||||
memcpy(newthing->bytes,bytes,4);
|
||||
searchfound= tsearch(newthing,&treeroot,comparer);
|
||||
if (!searchfound) sysfail("tsearch");
|
||||
foundthing= *searchfound;
|
||||
|
||||
if (foundthing == newthing) {
|
||||
newthing= 0;
|
||||
memcpy(&sa.sin_addr,bytes,4);
|
||||
r= adns_submit_reverse(ads, (const struct sockaddr*)&sa,
|
||||
rrt,0,foundthing,&foundthing->qu);
|
||||
if (r) adnsfail("submit",r);
|
||||
}
|
||||
entry= xmalloc(sizeof(*entry));
|
||||
entry->buffer= xmalloc(inbuf);
|
||||
entry->textp= entry->buffer;
|
||||
memcpy(entry->textp,addrtextbuf,inbuf);
|
||||
entry->textlen= inbuf;
|
||||
entry->addr= foundthing;
|
||||
entry->printbefore= printbefore;
|
||||
LIST_LINK_TAIL(outqueue,entry);
|
||||
outqueuelen++;
|
||||
inbuf= 0;
|
||||
cbyte= -1;
|
||||
}
|
||||
|
||||
static void startaddr(void) {
|
||||
bytes[cbyte=0]= 0;
|
||||
inbyte= 0;
|
||||
}
|
||||
|
||||
static void readstdin(void) {
|
||||
char readbuf[512], *p;
|
||||
int r, c, nbyte;
|
||||
|
||||
while ((r= read(0,readbuf,sizeof(readbuf))) <= 0) {
|
||||
if (r == 0) { inputeof= 1; return; }
|
||||
if (r == EAGAIN) return;
|
||||
if (r != EINTR) sysfail("read stdin");
|
||||
}
|
||||
for (p=readbuf; r>0; r--,p++) {
|
||||
c= *p;
|
||||
if (cbyte==-1 && bracket && c=='[') {
|
||||
addrtextbuf[inbuf++]= c;
|
||||
startaddr();
|
||||
} else if (cbyte==-1 && !bracket && !isalnum(c)) {
|
||||
queueoutchar(c);
|
||||
startaddr();
|
||||
} else if (cbyte>=0 && inbyte<3 && c>='0' && c<='9' &&
|
||||
(nbyte= bytes[cbyte]*10 + (c-'0')) <= 255) {
|
||||
bytes[cbyte]= nbyte;
|
||||
addrtextbuf[inbuf++]= c;
|
||||
inbyte++;
|
||||
} else if (cbyte>=0 && cbyte<3 && inbyte>0 && c=='.') {
|
||||
bytes[++cbyte]= 0;
|
||||
addrtextbuf[inbuf++]= c;
|
||||
inbyte= 0;
|
||||
} else if (cbyte==3 && inbyte>0 && bracket && c==']') {
|
||||
addrtextbuf[inbuf++]= c;
|
||||
procaddr();
|
||||
} else if (cbyte==3 && inbyte>0 && !bracket && !isalnum(c)) {
|
||||
procaddr();
|
||||
queueoutchar(c);
|
||||
startaddr();
|
||||
} else {
|
||||
restartbuf();
|
||||
queueoutchar(c);
|
||||
cbyte= -1;
|
||||
if (!bracket && !isalnum(c)) startaddr();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void startup(void) {
|
||||
int r;
|
||||
|
||||
if (nonblock(0,1)) sysfail("set stdin to nonblocking mode");
|
||||
if (nonblock(1,1)) sysfail("set stdout to nonblocking mode");
|
||||
memset(&sa,0,sizeof(sa));
|
||||
sa.sin_family= AF_INET;
|
||||
if (config_text) {
|
||||
r= adns_init_strcfg(&ads,initflags,stderr,config_text);
|
||||
} else {
|
||||
r= adns_init(&ads,initflags,0);
|
||||
}
|
||||
if (r) adnsfail("init",r);
|
||||
cbyte= -1;
|
||||
inbyte= -1;
|
||||
inbuf= 0;
|
||||
if (!bracket) startaddr();
|
||||
}
|
||||
|
||||
int main(int argc, const char *const *argv) {
|
||||
int r, maxfd;
|
||||
fd_set readfds, writefds, exceptfds;
|
||||
struct outqueuenode *entry;
|
||||
struct timeval *tv, tvbuf, now;
|
||||
|
||||
parseargs(argv);
|
||||
startup();
|
||||
|
||||
while (!inputeof || outqueue.head) {
|
||||
maxfd= 2;
|
||||
tv= 0;
|
||||
FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds);
|
||||
if ((entry= outqueue.head) && !outblocked) {
|
||||
if (!entry->addr) {
|
||||
writestdout(entry);
|
||||
continue;
|
||||
}
|
||||
if (entry->addr->ans) {
|
||||
if (entry->addr->ans->nrrs)
|
||||
replacetextwithname(entry);
|
||||
entry->addr= 0;
|
||||
continue;
|
||||
}
|
||||
r= gettimeofday(&now,0); if (r) sysfail("gettimeofday");
|
||||
if (forever) {
|
||||
tv= 0;
|
||||
} else if (!timercmp(&now,&entry->printbefore,<)) {
|
||||
entry->addr= 0;
|
||||
continue;
|
||||
} else {
|
||||
tvbuf.tv_sec= entry->printbefore.tv_sec - now.tv_sec - 1;
|
||||
tvbuf.tv_usec= entry->printbefore.tv_usec - now.tv_usec + 1000000;
|
||||
tvbuf.tv_sec += tvbuf.tv_usec / 1000000;
|
||||
tvbuf.tv_usec %= 1000000;
|
||||
tv= &tvbuf;
|
||||
}
|
||||
adns_beforeselect(ads,&maxfd,&readfds,&writefds,&exceptfds,
|
||||
&tv,&tvbuf,&now);
|
||||
}
|
||||
if (outblocked) FD_SET(1,&writefds);
|
||||
if (!inputeof && outqueuelen<1024) FD_SET(0,&readfds);
|
||||
|
||||
ADNS_CLEAR_ERRNO;
|
||||
r= select(maxfd,&readfds,&writefds,&exceptfds,tv);
|
||||
ADNS_CAPTURE_ERRNO;
|
||||
if (r < 0) { if (r == EINTR) continue; else sysfail("select"); }
|
||||
|
||||
r= gettimeofday(&now,0); if (r) sysfail("gettimeofday");
|
||||
adns_afterselect(ads,maxfd,&readfds,&writefds,&exceptfds,&now);
|
||||
checkadnsqueries();
|
||||
|
||||
if (FD_ISSET(0,&readfds)) {
|
||||
if (!forever) {
|
||||
printbefore= now;
|
||||
timevaladd(&printbefore,timeout);
|
||||
}
|
||||
readstdin();
|
||||
} else if (FD_ISSET(1,&writefds)) {
|
||||
outblocked= 0;
|
||||
}
|
||||
}
|
||||
if (nonblock(0,0)) sysfail("un-nonblock stdin");
|
||||
if (nonblock(1,0)) sysfail("un-nonblock stdout");
|
||||
adns_finish(ads);
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,346 @@
|
||||
/*
|
||||
* adnstest.c
|
||||
* - simple test program, not part of the library
|
||||
*/
|
||||
/*
|
||||
* This file is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
*
|
||||
* It is part of adns, which is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
* Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef ADNS_JGAA_WIN32
|
||||
# include "adns_win32.h"
|
||||
#else
|
||||
# include <stdio.h>
|
||||
# include <sys/time.h>
|
||||
# include <unistd.h>
|
||||
# include <assert.h>
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
# include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "adns.h"
|
||||
|
||||
#ifdef ADNS_REGRESS_TEST
|
||||
# include "hredirect.h"
|
||||
#endif
|
||||
|
||||
struct myctx {
|
||||
adns_query qu;
|
||||
int doneyet, found;
|
||||
const char *fdom;
|
||||
};
|
||||
|
||||
static struct myctx *mcs;
|
||||
static adns_state ads;
|
||||
static adns_rrtype *types_a;
|
||||
|
||||
static void quitnow(int rc) NONRETURNING;
|
||||
static void quitnow(int rc) {
|
||||
free(mcs);
|
||||
free(types_a);
|
||||
if (ads) adns_finish(ads);
|
||||
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
#ifndef HAVE_POLL
|
||||
#undef poll
|
||||
int poll(struct pollfd *ufds, int nfds, int timeout) {
|
||||
fputs("poll(2) not supported on this system\n",stderr);
|
||||
quitnow(5);
|
||||
return -1; /* compiler food */
|
||||
}
|
||||
#define adns_beforepoll(a,b,c,d,e) 0
|
||||
#define adns_afterpoll(a,b,c,d) 0
|
||||
#endif
|
||||
|
||||
static void failure_status(const char *what, adns_status st) NONRETURNING;
|
||||
static void failure_status(const char *what, adns_status st) {
|
||||
fprintf(stderr,"adns failure: %s: %s\n",what,adns_strerror(st));
|
||||
quitnow(2);
|
||||
}
|
||||
|
||||
static void failure_errno(const char *what, int errnoval) NONRETURNING;
|
||||
static void failure_errno(const char *what, int errnoval) {
|
||||
fprintf(stderr,"adns failure: %s: errno=%d\n",what,errnoval);
|
||||
quitnow(2);
|
||||
}
|
||||
|
||||
static void usageerr(const char *why) NONRETURNING;
|
||||
static void usageerr(const char *why) {
|
||||
fprintf(stderr,
|
||||
"bad usage: %s\n"
|
||||
"usage: adnstest [-<initflagsnum>[,<owninitflags>]] [/<initstring>]\n"
|
||||
" [ :<typenum>,... ]\n"
|
||||
" [ [<queryflagsnum>[,<ownqueryflags>]/]<domain> ... ]\n"
|
||||
"initflags: p use poll(2) instead of select(2)\n"
|
||||
" s use adns_wait with specified query, instead of 0\n"
|
||||
"queryflags: a print status abbrevs instead of strings\n"
|
||||
"exit status: 0 ok (though some queries may have failed)\n"
|
||||
" 1 used by test harness to indicate test failed\n"
|
||||
" 2 unable to submit or init or some such\n"
|
||||
" 3 unexpected failure\n"
|
||||
" 4 usage error\n"
|
||||
" 5 operation not supported on this system\n",
|
||||
why);
|
||||
quitnow(4);
|
||||
}
|
||||
|
||||
static const adns_rrtype defaulttypes[]= {
|
||||
adns_r_a,
|
||||
adns_r_ns_raw,
|
||||
adns_r_cname,
|
||||
adns_r_soa_raw,
|
||||
adns_r_ptr_raw,
|
||||
adns_r_hinfo,
|
||||
adns_r_mx_raw,
|
||||
adns_r_txt,
|
||||
adns_r_rp_raw,
|
||||
|
||||
adns_r_addr,
|
||||
adns_r_ns,
|
||||
adns_r_ptr,
|
||||
adns_r_mx,
|
||||
|
||||
adns_r_soa,
|
||||
adns_r_rp,
|
||||
|
||||
adns_r_none
|
||||
};
|
||||
|
||||
static void dumptype(adns_status ri, const char *rrtn, const char *fmtn) {
|
||||
fprintf(stdout, "%s(%s)%s%s",
|
||||
ri ? "?" : rrtn, ri ? "?" : fmtn ? fmtn : "-",
|
||||
ri ? " " : "", ri ? adns_strerror(ri) : "");
|
||||
}
|
||||
|
||||
static void fdom_split(const char *fdom, const char **dom_r, int *qf_r,
|
||||
char *ownflags, int ownflags_l) {
|
||||
int qf;
|
||||
char *ep;
|
||||
|
||||
qf= strtoul(fdom,&ep,0);
|
||||
if (*ep == ',' && strchr(ep,'/')) {
|
||||
ep++;
|
||||
while (*ep != '/') {
|
||||
if (--ownflags_l <= 0) { fputs("too many flags\n",stderr); quitnow(3); }
|
||||
*ownflags++= *ep++;
|
||||
}
|
||||
}
|
||||
if (*ep != '/') { *dom_r= fdom; *qf_r= 0; }
|
||||
else { *dom_r= ep+1; *qf_r= qf; }
|
||||
*ownflags= 0;
|
||||
}
|
||||
|
||||
static int consistsof(const char *string, const char *accept) {
|
||||
return strspn(string,accept) == strlen(string);
|
||||
}
|
||||
|
||||
int main(int argc, char *const *argv) {
|
||||
adns_query qu;
|
||||
struct myctx *mc, *mcw;
|
||||
void *mcr;
|
||||
adns_answer *ans;
|
||||
const char *initstring, *rrtn, *fmtn;
|
||||
const char *const *fdomlist, *domain;
|
||||
char *show, *cp;
|
||||
int len, i, qc, qi, tc, ti, ch, qflags, initflagsnum;
|
||||
adns_status ri;
|
||||
int r;
|
||||
const adns_rrtype *types;
|
||||
struct timeval now;
|
||||
char ownflags[10];
|
||||
char *ep;
|
||||
const char *initflags, *owninitflags;
|
||||
|
||||
if (argv[0] && argv[1] && argv[1][0] == '-') {
|
||||
initflags= argv[1]+1;
|
||||
argv++;
|
||||
} else {
|
||||
initflags= "";
|
||||
}
|
||||
if (argv[0] && argv[1] && argv[1][0] == '/') {
|
||||
initstring= argv[1]+1;
|
||||
argv++;
|
||||
} else {
|
||||
initstring= 0;
|
||||
}
|
||||
|
||||
initflagsnum= strtoul(initflags,&ep,0);
|
||||
if (*ep == ',') {
|
||||
owninitflags= ep+1;
|
||||
if (!consistsof(owninitflags,"ps")) usageerr("unknown owninitflag");
|
||||
} else if (!*ep) {
|
||||
owninitflags= "";
|
||||
} else {
|
||||
usageerr("bad <initflagsnum>[,<owninitflags>]");
|
||||
}
|
||||
|
||||
if (argv[0] && argv[1] && argv[1][0] == ':') {
|
||||
for (cp= argv[1]+1, tc=1; (ch= *cp); cp++)
|
||||
if (ch==',') tc++;
|
||||
types_a= malloc(sizeof(*types_a)*(tc+1));
|
||||
if (!types_a) { perror("malloc types"); quitnow(3); }
|
||||
for (cp= argv[1]+1, ti=0; ti<tc; ti++) {
|
||||
types_a[ti]= strtoul(cp,&cp,10);
|
||||
if ((ch= *cp)) {
|
||||
if (ch != ',') usageerr("unexpected char (not comma) in or between types");
|
||||
cp++;
|
||||
}
|
||||
}
|
||||
types_a[ti]= adns_r_none;
|
||||
types= types_a;
|
||||
argv++;
|
||||
} else {
|
||||
types_a= 0;
|
||||
types= defaulttypes;
|
||||
}
|
||||
|
||||
if (!(argv[0] && argv[1])) usageerr("no query domains supplied");
|
||||
fdomlist= (const char *const*)argv+1;
|
||||
|
||||
for (qc=0; fdomlist[qc]; qc++);
|
||||
for (tc=0; types[tc] != adns_r_none; tc++);
|
||||
mcs= malloc(tc ? sizeof(*mcs)*qc*tc : 1);
|
||||
if (!mcs) { perror("malloc mcs"); quitnow(3); }
|
||||
|
||||
setvbuf(stdout,0,_IOLBF,0);
|
||||
|
||||
if (initstring) {
|
||||
r= adns_init_strcfg(&ads,
|
||||
(adns_if_debug|adns_if_noautosys|adns_if_checkc_freq)
|
||||
^initflagsnum,
|
||||
stdout,initstring);
|
||||
} else {
|
||||
r= adns_init(&ads,
|
||||
(adns_if_debug|adns_if_noautosys)^initflagsnum,
|
||||
0);
|
||||
}
|
||||
if (r) failure_errno("init",r);
|
||||
|
||||
for (qi=0; qi<qc; qi++) {
|
||||
fdom_split(fdomlist[qi],&domain,&qflags,ownflags,sizeof(ownflags));
|
||||
if (!consistsof(ownflags,"a")) usageerr("unknown ownqueryflag");
|
||||
for (ti=0; ti<tc; ti++) {
|
||||
mc= &mcs[qi*tc+ti];
|
||||
mc->doneyet= 0;
|
||||
mc->fdom= fdomlist[qi];
|
||||
|
||||
fprintf(stdout,"%s flags %d type %d",domain,qflags,types[ti]);
|
||||
r= adns_submit(ads,domain,types[ti],qflags,mc,&mc->qu);
|
||||
if (r == ENOSYS) {
|
||||
fprintf(stdout," not implemented\n");
|
||||
mc->qu= 0;
|
||||
mc->doneyet= 1;
|
||||
} else if (r) {
|
||||
failure_errno("submit",r);
|
||||
} else {
|
||||
ri= adns_rr_info(types[ti], &rrtn,&fmtn,0, 0,0);
|
||||
putc(' ',stdout);
|
||||
dumptype(ri,rrtn,fmtn);
|
||||
fprintf(stdout," submitted\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
for (qi=0; qi<qc; qi++) {
|
||||
for (ti=0; ti<tc; ti++) {
|
||||
mc= &mcs[qi*tc+ti];
|
||||
mc->found= 0;
|
||||
}
|
||||
}
|
||||
for (adns_forallqueries_begin(ads);
|
||||
(qu= adns_forallqueries_next(ads,&mcr));
|
||||
) {
|
||||
mc= mcr;
|
||||
assert(qu == mc->qu);
|
||||
assert(!mc->doneyet);
|
||||
mc->found= 1;
|
||||
}
|
||||
mcw= 0;
|
||||
for (qi=0; qi<qc; qi++) {
|
||||
for (ti=0; ti<tc; ti++) {
|
||||
mc= &mcs[qi*tc+ti];
|
||||
if (mc->doneyet) continue;
|
||||
assert(mc->found);
|
||||
if (!mcw) mcw= mc;
|
||||
}
|
||||
}
|
||||
if (!mcw) break;
|
||||
|
||||
if (strchr(owninitflags,'s')) {
|
||||
qu= mcw->qu;
|
||||
mc= mcw;
|
||||
} else {
|
||||
qu= 0;
|
||||
mc= 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_POLL
|
||||
if (strchr(owninitflags,'p')) {
|
||||
r= adns_wait_poll(ads,&qu,&ans,&mcr);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
r= adns_wait(ads,&qu,&ans,&mcr);
|
||||
}
|
||||
if (r) failure_errno("wait/check",r);
|
||||
|
||||
if (mc) assert(mcr==mc);
|
||||
else mc= mcr;
|
||||
assert(qu==mc->qu);
|
||||
assert(!mc->doneyet);
|
||||
|
||||
fdom_split(mc->fdom,&domain,&qflags,ownflags,sizeof(ownflags));
|
||||
|
||||
if (gettimeofday(&now,0)) { perror("gettimeofday"); quitnow(3); }
|
||||
|
||||
ri= adns_rr_info(ans->type, &rrtn,&fmtn,&len, 0,0);
|
||||
fprintf(stdout, "%s flags %d type ",domain,qflags);
|
||||
dumptype(ri,rrtn,fmtn);
|
||||
fprintf(stdout, "%s%s: %s; nrrs=%d; cname=%s; owner=%s; ttl=%ld\n",
|
||||
ownflags[0] ? " ownflags=" : "", ownflags,
|
||||
strchr(ownflags,'a')
|
||||
? adns_errabbrev(ans->status)
|
||||
: adns_strerror(ans->status),
|
||||
ans->nrrs,
|
||||
ans->cname ? ans->cname : "$",
|
||||
ans->owner ? ans->owner : "$",
|
||||
(long)ans->expires - (long)now.tv_sec);
|
||||
if (ans->nrrs) {
|
||||
assert(!ri);
|
||||
for (i=0; i<ans->nrrs; i++) {
|
||||
ri= adns_rr_info(ans->type, 0,0,0, ans->rrs.bytes + i*len, &show);
|
||||
if (ri) failure_status("info",ri);
|
||||
fprintf(stdout," %s\n",show);
|
||||
free(show);
|
||||
}
|
||||
}
|
||||
free(ans);
|
||||
|
||||
mc->doneyet= 1;
|
||||
}
|
||||
|
||||
quitnow(0);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* clients.h
|
||||
* - useful declarations and definitions for adns client programs
|
||||
*/
|
||||
/*
|
||||
* This file is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
*
|
||||
* It is part of adns, which is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
* Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_H_INCLUDED
|
||||
#define CLIENT_H_INCLUDED
|
||||
|
||||
#define ADNS_VERSION_STRING "1.0"
|
||||
|
||||
#define COPYRIGHT_MESSAGE \
|
||||
"Copyright (C) 1997-2000 Ian Jackson <[email protected]>\n" \
|
||||
"Copyright (C) 1999-2000 Tony Finch <[email protected]>\n" \
|
||||
"This is free software; see the source for copying conditions. There is NO\n" \
|
||||
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
|
||||
|
||||
#define VERSION_MESSAGE(program) \
|
||||
program " (GNU adns) " ADNS_VERSION_STRING "\n\n" COPYRIGHT_MESSAGE
|
||||
|
||||
#define VERSION_PRINT_QUIT(program) \
|
||||
if (fputs(VERSION_MESSAGE(program),stdout) == EOF || \
|
||||
fclose(stdout)) { \
|
||||
perror(program ": write version message"); \
|
||||
quitnow(-1); \
|
||||
} \
|
||||
quitnow(0);
|
||||
|
||||
void quitnow(int rc) NONRETURNING;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* fanftest.c
|
||||
* - a small test program from Tony Finch
|
||||
*/
|
||||
/*
|
||||
* This file is
|
||||
* Copyright (C) 1999 Tony Finch <[email protected]>
|
||||
* Copyright (C) 1999-2000 Ian Jackson <[email protected]>
|
||||
*
|
||||
* It is part of adns, which is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
* Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* This version was originally supplied by Tony Finch, but has been
|
||||
* modified by Ian Jackson as it was incorporated into adns.
|
||||
*/
|
||||
|
||||
static const char * const cvsid =
|
||||
"$Id: fanftest.c,v 1.1 2003/12/18 10:48:20 arty Exp $";
|
||||
|
||||
#ifdef ADNS_JGAA_WIN32
|
||||
# include "adns_win32.h"
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
# include <sys/time.h>
|
||||
# include <string.h>
|
||||
# include <stdlib.h>
|
||||
# include <stdio.h>
|
||||
# include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "adns.h"
|
||||
|
||||
static const char *progname;
|
||||
|
||||
static void aargh(const char *msg) {
|
||||
fprintf(stderr, "%s: %s: %s (%d)\n", progname, msg,
|
||||
strerror(errno) ? strerror(errno) : "Unknown error", errno);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
adns_state adns;
|
||||
adns_query query;
|
||||
adns_answer *answer;
|
||||
|
||||
progname= strrchr(*argv, '/');
|
||||
if (progname)
|
||||
progname++;
|
||||
else
|
||||
progname= *argv;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "usage: %s <domain>\n", progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
errno= adns_init(&adns, adns_if_debug, 0);
|
||||
if (errno) aargh("adns_init");
|
||||
|
||||
errno= adns_submit(adns, argv[1], adns_r_ptr,
|
||||
adns_qf_quoteok_cname|adns_qf_cname_loose,
|
||||
NULL, &query);
|
||||
if (errno) aargh("adns_submit");
|
||||
|
||||
errno= adns_wait(adns, &query, &answer, NULL);
|
||||
if (errno) aargh("adns_init");
|
||||
|
||||
printf("%s\n", answer->status == adns_s_ok ? *answer->rrs.str : "dunno");
|
||||
|
||||
adns_finish(adns);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
# configure.in - input to autoconf
|
||||
#
|
||||
# This file is
|
||||
# Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
#
|
||||
# It is part of adns, which is
|
||||
# Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
# Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
AC_INIT(src/adns.h)
|
||||
AC_CONFIG_HEADER(src/config.h)
|
||||
|
||||
dnl DPKG_CACHED_TRY_COMPILE(<description>,<cachevar>,<include>,<program>,<ifyes>,<ifno>)
|
||||
define(DPKG_CACHED_TRY_COMPILE,[
|
||||
AC_MSG_CHECKING($1)
|
||||
AC_CACHE_VAL($2,[
|
||||
AC_TRY_COMPILE([$3],[$4],[$2=yes],[$2=no])
|
||||
])
|
||||
if test "x$$2" = xyes; then
|
||||
true
|
||||
$5
|
||||
else
|
||||
true
|
||||
$6
|
||||
fi
|
||||
])
|
||||
|
||||
AC_MSG_CHECKING(whether you requested dynamic linking)
|
||||
AC_SUBST(ENABLE_DYNAMIC)
|
||||
AC_ARG_ENABLE(dynamic,
|
||||
[ --disable-dynamic use static linking
|
||||
--enable-dynamic[=elf] create and use ELF dynamic library (default)],
|
||||
[ case "$enableval" in
|
||||
elf|yes)
|
||||
ENABLE_DYNAMIC=elf
|
||||
AC_MSG_RESULT([yes (ELF)])
|
||||
;;
|
||||
no) ENABLE_DYNAMIC=no
|
||||
AC_MSG_RESULT(no)
|
||||
;;
|
||||
*) AC_MSG_ERROR(
|
||||
["invalid value $enableval for --enable-dynamic, try yes or elf"])
|
||||
;;
|
||||
esac
|
||||
],[
|
||||
ENABLE_DYNAMIC=elf
|
||||
AC_MSG_RESULT([yes, by default])
|
||||
])
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_CPP
|
||||
AC_PROG_RANLIB
|
||||
AC_PROG_INSTALL
|
||||
|
||||
AC_CHECK_FUNCS(poll)
|
||||
ADNS_C_GETFUNC(socket,socket)
|
||||
ADNS_C_GETFUNC(inet_ntoa,nsl)
|
||||
|
||||
PROGS_IF_TSEARCH=adnsresfilter
|
||||
AC_SUBST(PROGS_HAVE_TSEARCH)
|
||||
AC_CHECK_FUNC(tsearch,[
|
||||
PROGS_HAVE_TSEARCH=$PROGS_IF_TSEARCH
|
||||
],[
|
||||
PROGS_HAVE_TSEARCH='';
|
||||
AC_MSG_WARN([tsearch missing - not building client program(s) $PROGS_IF_TSEARCH])
|
||||
])
|
||||
|
||||
AC_MSG_CHECKING(for INADDR_LOOPBACK)
|
||||
AC_CACHE_VAL(adns_cv_decl_inaddrloopback,[
|
||||
AC_TRY_COMPILE([
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
],[
|
||||
INADDR_LOOPBACK;
|
||||
],
|
||||
adns_cv_decl_inaddrloopback=yes,
|
||||
adns_cv_decl_inaddrloopback=no)])
|
||||
if test "$adns_cv_decl_inaddrloopback" = yes; then
|
||||
AC_MSG_RESULT(found)
|
||||
else
|
||||
AC_MSG_RESULT([not in standard headers, urgh...])
|
||||
AC_CHECK_HEADER(rpc/types.h,[
|
||||
AC_DEFINE(HAVEUSE_RPCTYPES_H)
|
||||
],[
|
||||
AC_MSG_ERROR([cannot find INADDR_LOOPBACK or rpc/types.h])
|
||||
])
|
||||
fi
|
||||
|
||||
ADNS_C_GETFUNC(inet_aton,resolv,[
|
||||
LIBS="-lresolv $LIBS";
|
||||
AC_MSG_WARN([inet_aton is in libresolv, urgh. Must use -lresolv.])
|
||||
])
|
||||
|
||||
DPKG_CACHED_TRY_COMPILE(inlines,dpkg_cv_c_inline,,
|
||||
[} inline int foo (int x) {],
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_INLINE),
|
||||
AC_MSG_RESULT(no))
|
||||
|
||||
ADNS_C_GCCATTRIB
|
||||
AC_CHECK_HEADERS(sys/select.h)
|
||||
|
||||
AC_SUBST(WARNS)
|
||||
|
||||
if test "${GCC-no}" = yes; then
|
||||
WARNS="-Wall -Wmissing-prototypes -Wwrite-strings -Wstrict-prototypes -Wcast-qual -Wpointer-arith"
|
||||
else
|
||||
WARNS=
|
||||
fi
|
||||
|
||||
AC_SUBST(SHLIBCC)
|
||||
AC_SUBST(MKSHLIB_1)
|
||||
AC_SUBST(MKSHLIB_2)
|
||||
AC_SUBST(MKSHLIB_3)
|
||||
|
||||
AC_SUBST(SHLIBFORLINK)
|
||||
AC_SUBST(SHLIBFILE)
|
||||
AC_SUBST(SHLIBSONAME)
|
||||
|
||||
SHLIBFORLINK='libadns.so'
|
||||
SHLIBSONAME='$(SHLIBFORLINK).$(MAJOR)'
|
||||
SHLIBFILE='$(SHLIBSONAME).$(MINOR)'
|
||||
|
||||
SHLIBCC='$(CC) $(CFLAGS) -fpic'
|
||||
MKSHLIB_1='$(CC) $(LDFLAGS) -shared -Wl,-soname=$(SHLIBSONAME) -o'
|
||||
MKSHLIB_2=''
|
||||
MKSHLIB_3='-lc'
|
||||
|
||||
AC_OUTPUT(
|
||||
settings.make Makefile
|
||||
src/Makefile client/Makefile dynamic/Makefile regress/Makefile
|
||||
)
|
||||
@@ -0,0 +1,54 @@
|
||||
# dynamic/Makefile - dynamic library Makefile
|
||||
#
|
||||
# This file is
|
||||
# Copyright (C) 1997-1999 Ian Jackson <[email protected]>
|
||||
#
|
||||
# It is part of adns, which is
|
||||
# Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
# Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
srcdir= @srcdir@
|
||||
VPATH= @srcdir@
|
||||
|
||||
TARGETS= $(SHLIBFILE) $(SHLIBSONAME) $(SHLIBFORLINK)
|
||||
include $(srcdir)/../settings.make
|
||||
include $(srcdir)/../src/adns.make
|
||||
|
||||
ALLOBJS= $(addsuffix _p.o, $(basename $(LIBOBJS)))
|
||||
|
||||
install:
|
||||
$(INSTALL_PROGRAM) $(SHLIBFILE) $(lib_dir)/$(SHLIBFILE)
|
||||
ln -sf $(SHLIBFILE) $(lib_dir)/$(SHLIBSONAME)
|
||||
|
||||
uninstall:
|
||||
rm -f $(lib_dir)/$(SHLIBFILE) $(lib_dir)/$(SHLIBSONAME)
|
||||
|
||||
$(SHLIBFORLINK):
|
||||
ln -s $(SHLIBSONAME) $(SHLIBFORLINK)
|
||||
|
||||
$(SHLIBSONAME):
|
||||
ln -s $(SHLIBFILE) $(SHLIBSONAME)
|
||||
|
||||
$(SHLIBFILE): $(ALLOBJS)
|
||||
rm -f $@
|
||||
$(MKSHLIB_1) $@ $(MKSHLIB_2) $(ALLOBJS) $(LDLIBS) $(MKSHLIB_3)
|
||||
|
||||
%_p.o: $(srcdir)/../src/%.c $(srcdir)/../src/adns.h \
|
||||
$(srcdir)/../src/internal.h $(srcdir)/../src/config.h
|
||||
$(SHLIBCC) -I$(srcdir)/../src -c -o $@ $<
|
||||
|
||||
$(LIBOBJS):
|
||||
Executable
+250
@@ -0,0 +1,250 @@
|
||||
#! /bin/sh
|
||||
#
|
||||
# install - install a program, script, or datafile
|
||||
# This comes from X11R5 (mit/util/scripts/install.sh).
|
||||
#
|
||||
# Copyright 1991 by the Massachusetts Institute of Technology
|
||||
#
|
||||
# Permission to use, copy, modify, distribute, and sell this software and its
|
||||
# documentation for any purpose is hereby granted without fee, provided that
|
||||
# the above copyright notice appear in all copies and that both that
|
||||
# copyright notice and this permission notice appear in supporting
|
||||
# documentation, and that the name of M.I.T. not be used in advertising or
|
||||
# publicity pertaining to distribution of the software without specific,
|
||||
# written prior permission. M.I.T. makes no representations about the
|
||||
# suitability of this software for any purpose. It is provided "as is"
|
||||
# without express or implied warranty.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# `make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch. It can only install one file at a time, a restriction
|
||||
# shared with many OS's install programs.
|
||||
|
||||
|
||||
# set DOITPROG to echo to test this script
|
||||
|
||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||
doit="${DOITPROG-}"
|
||||
|
||||
|
||||
# put in absolute paths if you don't have them in your path; or use env. vars.
|
||||
|
||||
mvprog="${MVPROG-mv}"
|
||||
cpprog="${CPPROG-cp}"
|
||||
chmodprog="${CHMODPROG-chmod}"
|
||||
chownprog="${CHOWNPROG-chown}"
|
||||
chgrpprog="${CHGRPPROG-chgrp}"
|
||||
stripprog="${STRIPPROG-strip}"
|
||||
rmprog="${RMPROG-rm}"
|
||||
mkdirprog="${MKDIRPROG-mkdir}"
|
||||
|
||||
transformbasename=""
|
||||
transform_arg=""
|
||||
instcmd="$mvprog"
|
||||
chmodcmd="$chmodprog 0755"
|
||||
chowncmd=""
|
||||
chgrpcmd=""
|
||||
stripcmd=""
|
||||
rmcmd="$rmprog -f"
|
||||
mvcmd="$mvprog"
|
||||
src=""
|
||||
dst=""
|
||||
dir_arg=""
|
||||
|
||||
while [ x"$1" != x ]; do
|
||||
case $1 in
|
||||
-c) instcmd="$cpprog"
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-d) dir_arg=true
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-m) chmodcmd="$chmodprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-s) stripcmd="$stripprog"
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
*) if [ x"$src" = x ]
|
||||
then
|
||||
src=$1
|
||||
else
|
||||
# this colon is to work around a 386BSD /bin/sh bug
|
||||
:
|
||||
dst=$1
|
||||
fi
|
||||
shift
|
||||
continue;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ x"$src" = x ]
|
||||
then
|
||||
echo "install: no input file specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]; then
|
||||
dst=$src
|
||||
src=""
|
||||
|
||||
if [ -d $dst ]; then
|
||||
instcmd=:
|
||||
else
|
||||
instcmd=mkdir
|
||||
fi
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
|
||||
if [ -f $src -o -d $src ]
|
||||
then
|
||||
true
|
||||
else
|
||||
echo "install: $src does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ x"$dst" = x ]
|
||||
then
|
||||
echo "install: no destination specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
# If destination is a directory, append the input filename; if your system
|
||||
# does not like double slashes in filenames, you may need to add some logic
|
||||
|
||||
if [ -d $dst ]
|
||||
then
|
||||
dst="$dst"/`basename $src`
|
||||
else
|
||||
true
|
||||
fi
|
||||
fi
|
||||
|
||||
## this sed command emulates the dirname command
|
||||
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
|
||||
|
||||
# Make sure that the destination directory exists.
|
||||
# this part is taken from Noah Friedman's mkinstalldirs script
|
||||
|
||||
# Skip lots of stat calls in the usual case.
|
||||
if [ ! -d "$dstdir" ]; then
|
||||
defaultIFS='
|
||||
'
|
||||
IFS="${IFS-${defaultIFS}}"
|
||||
|
||||
oIFS="${IFS}"
|
||||
# Some sh's can't handle IFS=/ for some reason.
|
||||
IFS='%'
|
||||
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
|
||||
IFS="${oIFS}"
|
||||
|
||||
pathcomp=''
|
||||
|
||||
while [ $# -ne 0 ] ; do
|
||||
pathcomp="${pathcomp}${1}"
|
||||
shift
|
||||
|
||||
if [ ! -d "${pathcomp}" ] ;
|
||||
then
|
||||
$mkdirprog "${pathcomp}"
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
pathcomp="${pathcomp}/"
|
||||
done
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]
|
||||
then
|
||||
$doit $instcmd $dst &&
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
|
||||
else
|
||||
|
||||
# If we're going to rename the final executable, determine the name now.
|
||||
|
||||
if [ x"$transformarg" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
dstfile=`basename $dst $transformbasename |
|
||||
sed $transformarg`$transformbasename
|
||||
fi
|
||||
|
||||
# don't allow the sed command to completely eliminate the filename
|
||||
|
||||
if [ x"$dstfile" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
# Make a temp file name in the proper directory.
|
||||
|
||||
dsttmp=$dstdir/#inst.$$#
|
||||
|
||||
# Move or copy the file name to the temp name
|
||||
|
||||
$doit $instcmd $src $dsttmp &&
|
||||
|
||||
trap "rm -f ${dsttmp}" 0 &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits
|
||||
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $instcmd $src $dsttmp" command.
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
|
||||
$doit $rmcmd -f $dstdir/$dstfile &&
|
||||
$doit $mvcmd $dsttmp $dstdir/$dstfile
|
||||
|
||||
fi &&
|
||||
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,76 @@
|
||||
# settings.make.in - main configuration settings for Makefiles,
|
||||
# used by autoconf/configure to generate settings.make
|
||||
#
|
||||
# This file is
|
||||
# Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
#
|
||||
# It is part of adns, which is
|
||||
# Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
# Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
MAJOR= 1
|
||||
MINOR= 0
|
||||
SHLIBFILE= @SHLIBFILE@
|
||||
SHLIBSONAME= @SHLIBSONAME@
|
||||
SHLIBFORLINK= @SHLIBFORLINK@
|
||||
|
||||
CC= @CC@
|
||||
CFLAGS= $(AUTOCFLAGS) $(WARNS) $(WERROR) $(DIRCFLAGS) $(XCFLAGS)
|
||||
LDFLAGS= $(AUTOLDFLAGS) $(DIRLDFLAGS) $(XLDFLAGS)
|
||||
LDLIBS= @LIBS@ $(XLIBS)
|
||||
AUTOCFLAGS= @CFLAGS@
|
||||
AUTOLDFLAGS= @LDFLAGS@
|
||||
WARNS= @WARNS@
|
||||
#WERROR= -Werror
|
||||
|
||||
M4= m4
|
||||
RANLIB= @RANLIB@
|
||||
|
||||
SHLIBCC= @SHLIBCC@
|
||||
|
||||
MKSHLIB_1= @MKSHLIB_1@
|
||||
MKSHLIB_2= @MKSHLIB_2@
|
||||
MKSHLIB_3= @MKSHLIB_3@
|
||||
|
||||
prefix= @prefix@
|
||||
exec_prefix= @exec_prefix@
|
||||
bin_dir= $(exec_prefix)/bin
|
||||
lib_dir= $(exec_prefix)/lib
|
||||
include_dir= $(prefix)/include
|
||||
|
||||
AC_INSTALL= @INSTALL@
|
||||
ifeq ($(AC_INSTALL),./install-sh -c)
|
||||
INSTALL= $(srcdir)/../$(AC_INSTALL)
|
||||
else
|
||||
INSTALL= $(AC_INSTALL)
|
||||
endif
|
||||
|
||||
INSTALL_PROGRAM= $(INSTALL) -m 755 $(INSTALL_PROGRAM_FLAGS)
|
||||
INSTALL_DATA= $(INSTALL) -m 644
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
clean mostlyclean:
|
||||
rm -f *.o *.tmp* *.so *.so.*
|
||||
|
||||
distclean: clean
|
||||
rm -f $(TARGETS) *~ ./#*# core *.orig *.rej Makefile
|
||||
|
||||
distprep: $(AUTOCSRCS) $(AUTOCHDRS)
|
||||
|
||||
maintainer-clean: distclean
|
||||
-rm -f $(AUTOCSRCS) $(AUTOCHDRS)
|
||||
@@ -0,0 +1,48 @@
|
||||
# src/Makefile - library main Makefile
|
||||
#
|
||||
# This file is
|
||||
# Copyright (C) 1997-1999 Ian Jackson <[email protected]>
|
||||
#
|
||||
# It is part of adns, which is
|
||||
# Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
# Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
srcdir= @srcdir@
|
||||
VPATH= @srcdir@
|
||||
|
||||
TARGETS= libadns.a
|
||||
include $(srcdir)/../settings.make
|
||||
include adns.make
|
||||
|
||||
install:
|
||||
set -xe; for f in $(TARGETS); \
|
||||
do $(INSTALL_DATA) $$f $(lib_dir)/$$f; done
|
||||
$(INSTALL_DATA) $(srcdir)/../src/adns.h $(include_dir)/adns.h
|
||||
|
||||
uninstall:
|
||||
for f in $(TARGETS); do rm -f $(lib_dir)/$$f; done
|
||||
rm -f $(include_dir)/adns.h
|
||||
|
||||
ALLOBJS= $(LIBOBJS)
|
||||
|
||||
libadns.a: $(LIBOBJS)
|
||||
rm -f $@
|
||||
$(AR) cqv $@.new $(LIBOBJS)
|
||||
$(RANLIB) $@.new
|
||||
mv -f $@.new $@
|
||||
|
||||
$(LIBOBJS): adns.h internal.h config.h
|
||||
@@ -0,0 +1,859 @@
|
||||
/*
|
||||
* adns.h
|
||||
* - adns user-visible API (single-threaded, without any locking)
|
||||
*/
|
||||
/*
|
||||
*
|
||||
* This file is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
*
|
||||
* It is part of adns, which is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
* Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* For the benefit of certain LGPL'd `omnibus' software which
|
||||
* provides a uniform interface to various things including adns, I
|
||||
* make the following additional licence. I do this because the GPL
|
||||
* would otherwise force either the omnibus software to be GPL'd or
|
||||
* the adns-using part to be distributed separately.
|
||||
*
|
||||
* So: you may also redistribute and/or modify adns.h (but only the
|
||||
* public header file adns.h and not any other part of adns) under the
|
||||
* terms of the GNU Library General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Note that adns itself is GPL'd. Authors of adns-using applications
|
||||
* with GPL-incompatible licences, and people who distribute adns with
|
||||
* applications where the whole distribution is not GPL'd, are still
|
||||
* likely to be in violation of the GPL. Anyone who wants to do this
|
||||
* should contact Ian Jackson. Please note that to avoid encouraging
|
||||
* people to infringe the GPL as it applies to the body of adns, Ian
|
||||
* thinks that if you take advantage of the special exception to
|
||||
* redistribute just adns.h under the LGPL, you should retain this
|
||||
* paragraph in its place in the appropriate copyright statements.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License,
|
||||
* or the GNU Library General Public License, as appropriate, along
|
||||
* with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*
|
||||
* $Id: adns.h,v 1.1 2003/12/18 10:48:20 arty Exp $
|
||||
*/
|
||||
|
||||
#ifndef ADNS_H_INCLUDED
|
||||
#define ADNS_H_INCLUDED
|
||||
|
||||
#ifdef ADNS_JGAA_WIN32
|
||||
# include "adns_win32.h"
|
||||
#else
|
||||
# include <stdio.h>
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/time.h>
|
||||
# include <unistd.h>
|
||||
|
||||
# define ADNS_API
|
||||
# define ADNS_SOCKET int
|
||||
# define adns_socket_close(sck) close(sck)
|
||||
# define adns_socket_read(sck, data, len) read(sck, data, len)
|
||||
# define adns_socket_write(sck, data, len) write(sck, data, len)
|
||||
# define ADNS_CAPTURE_ERRNO {}
|
||||
# define ADNS_CLEAR_ERRNO {}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" { /* I really dislike this - iwj. */
|
||||
#endif
|
||||
|
||||
/* All struct in_addr anywhere in adns are in NETWORK byte order. */
|
||||
|
||||
typedef struct adns__state *adns_state;
|
||||
typedef struct adns__query *adns_query;
|
||||
|
||||
typedef enum {
|
||||
adns_if_noenv= 0x0001, /* do not look at environment */
|
||||
adns_if_noerrprint= 0x0002, /* never print output to stderr (_debug overrides) */
|
||||
adns_if_noserverwarn= 0x0004, /* do not warn to stderr about duff nameservers etc */
|
||||
adns_if_debug= 0x0008, /* enable all output to stderr plus debug msgs */
|
||||
adns_if_logpid= 0x0080, /* include pid in diagnostic output */
|
||||
adns_if_noautosys= 0x0010, /* do not make syscalls at every opportunity */
|
||||
adns_if_eintr= 0x0020, /* allow _wait and _synchronous to return EINTR */
|
||||
adns_if_nosigpipe= 0x0040, /* applic has SIGPIPE set to SIG_IGN, do not protect */
|
||||
adns_if_checkc_entex= 0x0100, /* do consistency checks on entry/exit to adns funcs */
|
||||
adns_if_checkc_freq= 0x0300 /* do consistency checks very frequently (slow!) */
|
||||
} adns_initflags;
|
||||
|
||||
typedef enum {
|
||||
adns_qf_search= 0x00000001, /* use the searchlist */
|
||||
adns_qf_usevc= 0x00000002, /* use a virtual circuit (TCP connection) */
|
||||
adns_qf_owner= 0x00000004, /* fill in the owner field in the answer */
|
||||
adns_qf_quoteok_query= 0x00000010, /* allow special chars in query domain */
|
||||
adns_qf_quoteok_cname= 0x00000000, /* allow ... in CNAME we go via - now default */
|
||||
adns_qf_quoteok_anshost= 0x00000040, /* allow ... in things supposed to be hostnames */
|
||||
adns_qf_quotefail_cname= 0x00000080, /* refuse if quote-req chars in CNAME we go via */
|
||||
adns_qf_cname_loose= 0x00000100, /* allow refs to CNAMEs - without, get _s_cname */
|
||||
adns_qf_cname_forbid= 0x00000200, /* don't follow CNAMEs, instead give _s_cname */
|
||||
adns__qf_internalmask= 0x0ff00000
|
||||
} adns_queryflags;
|
||||
|
||||
typedef enum {
|
||||
adns__rrt_typemask= 0x0ffff,
|
||||
adns__qtf_deref= 0x10000, /* dereference domains and perhaps produce extra data */
|
||||
adns__qtf_mail822= 0x20000, /* make mailboxes be in RFC822 rcpt field format */
|
||||
|
||||
adns_r_none= 0,
|
||||
|
||||
adns_r_a= 1,
|
||||
|
||||
adns_r_ns_raw= 2,
|
||||
adns_r_ns= adns_r_ns_raw|adns__qtf_deref,
|
||||
|
||||
adns_r_cname= 5,
|
||||
|
||||
adns_r_soa_raw= 6,
|
||||
adns_r_soa= adns_r_soa_raw|adns__qtf_mail822,
|
||||
|
||||
adns_r_ptr_raw= 12,
|
||||
adns_r_ptr= adns_r_ptr_raw|adns__qtf_deref,
|
||||
|
||||
adns_r_hinfo= 13,
|
||||
|
||||
adns_r_mx_raw= 15,
|
||||
adns_r_mx= adns_r_mx_raw|adns__qtf_deref,
|
||||
|
||||
adns_r_txt= 16,
|
||||
|
||||
adns_r_rp_raw= 17,
|
||||
adns_r_rp= adns_r_rp_raw|adns__qtf_mail822,
|
||||
|
||||
adns_r_addr= adns_r_a|adns__qtf_deref
|
||||
|
||||
} adns_rrtype;
|
||||
|
||||
/*
|
||||
* In queries without qf_quoteok_*, all domains must have standard
|
||||
* legal syntax, or you get adns_s_querydomainvalid (if the query
|
||||
* domain contains bad characters) or adns_s_answerdomaininvalid (if
|
||||
* the answer contains bad characters).
|
||||
*
|
||||
* In queries _with_ qf_quoteok_*, domains in the query or response
|
||||
* may contain any characters, quoted according to RFC1035 5.1. On
|
||||
* input to adns, the char* is a pointer to the interior of a "
|
||||
* delimited string, except that " may appear in it unquoted. On
|
||||
* output, the char* is a pointer to a string which would be legal
|
||||
* either inside or outside " delimiters; any character which isn't
|
||||
* legal in a hostname (ie alphanumeric or hyphen) or one of _ / +
|
||||
* (the three other punctuation characters commonly abused in domain
|
||||
* names) will be quoted, as \X if it is a printing ASCII character or
|
||||
* \DDD otherwise.
|
||||
*
|
||||
* If the query goes via a CNAME then the canonical name (ie, the
|
||||
* thing that the CNAME record refers to) is usually allowed to
|
||||
* contain any characters, which will be quoted as above. With
|
||||
* adns_qf_quotefail_cname you get adns_s_answerdomaininvalid when
|
||||
* this happens. (This is a change from version 0.4 and earlier, in
|
||||
* which failing the query was the default, and you had to say
|
||||
* adns_qf_quoteok_cname to avoid this; that flag is now deprecated.)
|
||||
*
|
||||
* In version 0.4 and earlier, asking for _raw records containing
|
||||
* mailboxes without specifying _qf_quoteok_anshost was silly. This
|
||||
* is no longer the case. In this version only parts of responses
|
||||
* that are actually supposed to be hostnames will be refused by
|
||||
* default if quote-requiring characters are found.
|
||||
*/
|
||||
|
||||
/*
|
||||
* If you ask for an RR which contains domains which are actually
|
||||
* encoded mailboxes, and don't ask for the _raw version, then adns
|
||||
* returns the mailbox formatted suitably for an RFC822 recipient
|
||||
* header field. The particular format used is that if the mailbox
|
||||
* requires quoting according to the rules in RFC822 then the
|
||||
* local-part is quoted in double quotes, which end at the next
|
||||
* unescaped double quote (\ is the escape char, and is doubled, and
|
||||
* is used to escape only \ and "). If the local-part is legal
|
||||
* without quoting according to RFC822, it is presented as-is. In any
|
||||
* case the local-part is followed by an @ and the domain. The domain
|
||||
* will not contain any characters not legal in hostnames.
|
||||
*
|
||||
* Unquoted local-parts may contain any printing 7-bit ASCII
|
||||
* except the punctuation characters ( ) < > @ , ; : \ " [ ]
|
||||
* I.e. they may contain alphanumerics, and the following
|
||||
* punctuation characters: ! # % ^ & * - _ = + { } .
|
||||
*
|
||||
* adns will reject local parts containing control characters (byte
|
||||
* values 0-31, 127-159, and 255) - these appear to be legal according
|
||||
* to RFC822 (at least 0-127) but are clearly a bad idea. RFC1035
|
||||
* syntax does not make any distinction between a single RFC822
|
||||
* quoted-string containing full stops, and a series of quoted-strings
|
||||
* separated by full stops; adns will return anything that isn't all
|
||||
* valid atoms as a single quoted-string. RFC822 does not allow
|
||||
* high-bit-set characters at all, but adns does allow them in
|
||||
* local-parts, treating them as needing quoting.
|
||||
*
|
||||
* If you ask for the domain with _raw then _no_ checking is done
|
||||
* (even on the host part, regardless of adns_qf_quoteok_anshost), and
|
||||
* you just get the domain name in master file format.
|
||||
*
|
||||
* If no mailbox is supplied the returned string will be `.' in either
|
||||
* case.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
adns_s_ok,
|
||||
|
||||
/* locally induced errors */
|
||||
adns_s_nomemory,
|
||||
adns_s_unknownrrtype,
|
||||
adns_s_systemfail,
|
||||
|
||||
adns_s_max_localfail= 29,
|
||||
|
||||
/* remotely induced errors, detected locally */
|
||||
adns_s_timeout,
|
||||
adns_s_allservfail,
|
||||
adns_s_norecurse,
|
||||
adns_s_invalidresponse,
|
||||
adns_s_unknownformat,
|
||||
|
||||
adns_s_max_remotefail= 59,
|
||||
|
||||
/* remotely induced errors, reported by remote server to us */
|
||||
adns_s_rcodeservfail,
|
||||
adns_s_rcodeformaterror,
|
||||
adns_s_rcodenotimplemented,
|
||||
adns_s_rcoderefused,
|
||||
adns_s_rcodeunknown,
|
||||
|
||||
adns_s_max_tempfail= 99,
|
||||
|
||||
/* remote configuration errors */
|
||||
adns_s_inconsistent, /* PTR gives domain whose A does not exist and match */
|
||||
adns_s_prohibitedcname, /* CNAME found where eg A expected (not if _qf_loosecname) */
|
||||
adns_s_answerdomaininvalid,
|
||||
adns_s_answerdomaintoolong,
|
||||
adns_s_invaliddata,
|
||||
|
||||
adns_s_max_misconfig= 199,
|
||||
|
||||
/* permanent problems with the query */
|
||||
adns_s_querydomainwrong,
|
||||
adns_s_querydomaininvalid,
|
||||
adns_s_querydomaintoolong,
|
||||
|
||||
adns_s_max_misquery= 299,
|
||||
|
||||
/* permanent errors */
|
||||
adns_s_nxdomain,
|
||||
adns_s_nodata,
|
||||
|
||||
adns_s_max_permfail= 499
|
||||
|
||||
} adns_status;
|
||||
|
||||
typedef struct {
|
||||
int len;
|
||||
union {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in inet;
|
||||
} addr;
|
||||
} adns_rr_addr;
|
||||
|
||||
typedef struct {
|
||||
char *host;
|
||||
adns_status astatus;
|
||||
int naddrs; /* temp fail => -1, perm fail => 0, s_ok => >0 */
|
||||
adns_rr_addr *addrs;
|
||||
} adns_rr_hostaddr;
|
||||
|
||||
typedef struct {
|
||||
char *(array[2]);
|
||||
} adns_rr_strpair;
|
||||
|
||||
typedef struct {
|
||||
int i;
|
||||
adns_rr_hostaddr ha;
|
||||
} adns_rr_inthostaddr;
|
||||
|
||||
typedef struct {
|
||||
/* Used both for mx_raw, in which case i is the preference and str the domain,
|
||||
* and for txt, in which case each entry has i for the `text' length,
|
||||
* and str for the data (which will have had an extra nul appended
|
||||
* so that if it was plain text it is now a null-terminated string).
|
||||
*/
|
||||
int i;
|
||||
char *str;
|
||||
} adns_rr_intstr;
|
||||
|
||||
typedef struct {
|
||||
adns_rr_intstr array[2];
|
||||
} adns_rr_intstrpair;
|
||||
|
||||
typedef struct {
|
||||
char *mname, *rname;
|
||||
unsigned long serial, refresh, retry, expire, minimum;
|
||||
} adns_rr_soa;
|
||||
|
||||
typedef struct {
|
||||
adns_status status;
|
||||
char *cname; /* always NULL if query was for CNAME records */
|
||||
char *owner; /* only set if requested in query flags, and may be 0 on error anyway */
|
||||
adns_rrtype type; /* guaranteed to be same as in query */
|
||||
time_t expires; /* expiry time, defined only if _s_ok, nxdomain or nodata. NOT TTL! */
|
||||
int nrrs, rrsz; /* nrrs is 0 if an error occurs */
|
||||
union {
|
||||
void *untyped;
|
||||
unsigned char *bytes;
|
||||
char *(*str); /* ns_raw, cname, ptr, ptr_raw */
|
||||
adns_rr_intstr *(*manyistr); /* txt (list of strings ends with i=-1, str=0) */
|
||||
adns_rr_addr *addr; /* addr */
|
||||
struct in_addr *inaddr; /* a */
|
||||
adns_rr_hostaddr *hostaddr; /* ns */
|
||||
adns_rr_intstrpair *intstrpair; /* hinfo */
|
||||
adns_rr_strpair *strpair; /* rp, rp_raw */
|
||||
adns_rr_inthostaddr *inthostaddr; /* mx */
|
||||
adns_rr_intstr *intstr; /* mx_raw */
|
||||
adns_rr_soa *soa; /* soa, soa_raw */
|
||||
} rrs;
|
||||
} adns_answer;
|
||||
|
||||
/* Memory management:
|
||||
* adns_state and adns_query are actually pointers to malloc'd state;
|
||||
* On submission questions are copied, including the owner domain;
|
||||
* Answers are malloc'd as a single piece of memory; pointers in the
|
||||
* answer struct point into further memory in the answer.
|
||||
* query_io:
|
||||
* Must always be non-null pointer;
|
||||
* If *query_io is 0 to start with then any query may be returned;
|
||||
* If *query_io is !0 adns_query then only that query may be returned.
|
||||
* If the call is successful, *query_io, *answer_r, and *context_r
|
||||
* will all be set.
|
||||
* Errors:
|
||||
* Return values are 0 or an errno value.
|
||||
*
|
||||
* For _init, _init_strcfg, _submit and _synchronous, system errors
|
||||
* (eg, failure to create sockets, malloc failure, etc.) return errno
|
||||
* values.
|
||||
*
|
||||
* For _wait and _check failures are reported in the answer
|
||||
* structure, and only 0, ESRCH or (for _check) EAGAIN is
|
||||
* returned: if no (appropriate) requests are done adns_check returns
|
||||
* EAGAIN; if no (appropriate) requests are outstanding both
|
||||
* adns_query and adns_wait return ESRCH.
|
||||
*
|
||||
* Additionally, _wait can return EINTR if you set adns_if_eintr.
|
||||
*
|
||||
* All other errors (nameserver failure, timed out connections, &c)
|
||||
* are returned in the status field of the answer. After a
|
||||
* successful _wait or _check, if status is nonzero then nrrs will be
|
||||
* 0, otherwise it will be >0. type will always be the type
|
||||
* requested.
|
||||
*/
|
||||
|
||||
ADNS_API int adns_init(adns_state *newstate_r, adns_initflags flags,
|
||||
FILE *diagfile /*0=>stderr*/);
|
||||
|
||||
ADNS_API int adns_init_strcfg(adns_state *newstate_r, adns_initflags flags,
|
||||
FILE *diagfile /*0=>discard*/, const char *configtext);
|
||||
|
||||
/* Configuration:
|
||||
* adns_init reads /etc/resolv.conf, which is expected to be (broadly
|
||||
* speaking) in the format expected by libresolv, and then
|
||||
* /etc/resolv-adns.conf if it exists. adns_init_strcfg is instead
|
||||
* passed a string which is interpreted as if it were the contents of
|
||||
* resolv.conf or resolv-adns.conf. In general, configuration which
|
||||
* is set later overrides any that is set earlier.
|
||||
*
|
||||
* Standard directives understood in resolv[-adns].conf:
|
||||
*
|
||||
* nameserver <address>
|
||||
* Must be followed by the IP address of a nameserver. Several
|
||||
* nameservers may be specified, and they will be tried in the order
|
||||
* found. There is a compiled in limit, currently 5, on the number
|
||||
* of nameservers. (libresolv supports only 3 nameservers.)
|
||||
*
|
||||
* search <domain> ...
|
||||
* Specifies the search list for queries which specify
|
||||
* adns_qf_search. This is a list of domains to append to the query
|
||||
* domain. The query domain will be tried as-is either before all
|
||||
* of these or after them, depending on the ndots option setting
|
||||
* (see below).
|
||||
*
|
||||
* domain <domain>
|
||||
* This is present only for backward compatibility with obsolete
|
||||
* versions of libresolv. It should not be used, and is interpreted
|
||||
* by adns as if it were `search' - note that this is subtly
|
||||
* different to libresolv's interpretation of this directive.
|
||||
*
|
||||
* sortlist <addr>/<mask> ...
|
||||
* Should be followed by a sequence of IP-address and netmask pairs,
|
||||
* separated by spaces. They may be specified as
|
||||
* eg. 172.30.206.0/24 or 172.30.206.0/255.255.255.0. Currently up
|
||||
* to 15 pairs may be specified (but note that libresolv only
|
||||
* supports up to 10).
|
||||
*
|
||||
* options
|
||||
* Should followed by one or more options, separated by spaces.
|
||||
* Each option consists of an option name, followed by optionally
|
||||
* a colon and a value. Options are listed below.
|
||||
*
|
||||
* Non-standard directives understood in resolv[-adns].conf:
|
||||
*
|
||||
* clearnameservers
|
||||
* Clears the list of nameservers, so that further nameserver lines
|
||||
* start again from the beginning.
|
||||
*
|
||||
* include <filename>
|
||||
* The specified file will be read.
|
||||
*
|
||||
* Additionally, adns will ignore lines in resolv[-adns].conf which
|
||||
* start with a #.
|
||||
*
|
||||
* Standard options understood:
|
||||
*
|
||||
* debug
|
||||
* Enables debugging output from the resolver, which will be written
|
||||
* to stderr.
|
||||
*
|
||||
* ndots:<count>
|
||||
* Affects whether queries with adns_qf_search will be tried first
|
||||
* without adding domains from the searchlist, or whether the bare
|
||||
* query domain will be tried last. Queries which contain at least
|
||||
* <count> dots will be tried bare first. The default is 1.
|
||||
*
|
||||
* Non-standard options understood:
|
||||
*
|
||||
* adns_checkc:none
|
||||
* adns_checkc:entex
|
||||
* adns_checkc:freq
|
||||
* Changes the consistency checking frequency; this overrides the
|
||||
* setting of adns_if_check_entex, adns_if_check_freq, or neither,
|
||||
* in the flags passed to adns_init.
|
||||
*
|
||||
* There are a number of environment variables which can modify the
|
||||
* behaviour of adns. They take effect only if adns_init is used, and
|
||||
* the caller of adns_init can disable them using adns_if_noenv. In
|
||||
* each case there is both a FOO and an ADNS_FOO; the latter is
|
||||
* interpreted later so that it can override the former. Unless
|
||||
* otherwise stated, environment variables are interpreted after
|
||||
* resolv[-adns].conf are read, in the order they are listed here.
|
||||
*
|
||||
* RES_CONF, ADNS_RES_CONF
|
||||
* A filename, whose contets are in the format of resolv.conf.
|
||||
*
|
||||
* RES_CONF_TEXT, ADNS_RES_CONF_TEXT
|
||||
* A string in the format of resolv.conf.
|
||||
*
|
||||
* RES_OPTIONS, ADNS_RES_OPTIONS
|
||||
* These are parsed as if they appeared in the `options' line of a
|
||||
* resolv.conf. In addition to being parsed at this point in the
|
||||
* sequence, they are also parsed at the very beginning before
|
||||
* resolv.conf or any other environment variables are read, so that
|
||||
* any debug option can affect the processing of the configuration.
|
||||
*
|
||||
* LOCALDOMAIN, ADNS_LOCALDOMAIN
|
||||
* These are interpreted as if their contents appeared in a `search'
|
||||
* line in resolv.conf.
|
||||
*/
|
||||
|
||||
ADNS_API int adns_synchronous(adns_state ads,
|
||||
const char *owner,
|
||||
adns_rrtype type,
|
||||
adns_queryflags flags,
|
||||
adns_answer **answer_r);
|
||||
|
||||
/* NB: if you set adns_if_noautosys then _submit and _check do not
|
||||
* make any system calls; you must use some of the asynch-io event
|
||||
* processing functions to actually get things to happen.
|
||||
*/
|
||||
|
||||
ADNS_API int adns_submit(adns_state ads,
|
||||
const char *owner,
|
||||
adns_rrtype type,
|
||||
adns_queryflags flags,
|
||||
void *context,
|
||||
adns_query *query_r);
|
||||
|
||||
/* The owner should be quoted in master file format. */
|
||||
|
||||
ADNS_API int adns_check(adns_state ads,
|
||||
adns_query *query_io,
|
||||
adns_answer **answer_r,
|
||||
void **context_r);
|
||||
|
||||
ADNS_API int adns_wait(adns_state ads,
|
||||
adns_query *query_io,
|
||||
adns_answer **answer_r,
|
||||
void **context_r);
|
||||
|
||||
/* same as adns_wait but uses poll(2) internally */
|
||||
ADNS_API int adns_wait_poll(adns_state ads,
|
||||
adns_query *query_io,
|
||||
adns_answer **answer_r,
|
||||
void **context_r);
|
||||
|
||||
ADNS_API void adns_cancel(adns_query query);
|
||||
|
||||
/* The adns_query you get back from _submit is valid (ie, can be
|
||||
* legitimately passed into adns functions) until it is returned by
|
||||
* adns_check or adns_wait, or passed to adns_cancel. After that it
|
||||
* must not be used. You can rely on it not being reused until the
|
||||
* first adns_submit or _transact call using the same adns_state after
|
||||
* it became invalid, so you may compare it for equality with other
|
||||
* query handles until you next call _query or _transact.
|
||||
*
|
||||
* _submit and _synchronous return ENOSYS if they don't understand the
|
||||
* query type.
|
||||
*/
|
||||
|
||||
ADNS_API int adns_submit_reverse(adns_state ads,
|
||||
const struct sockaddr *addr,
|
||||
adns_rrtype type,
|
||||
adns_queryflags flags,
|
||||
void *context,
|
||||
adns_query *query_r);
|
||||
/* type must be _r_ptr or _r_ptr_raw. _qf_search is ignored.
|
||||
* addr->sa_family must be AF_INET or you get ENOSYS.
|
||||
*/
|
||||
|
||||
ADNS_API int adns_submit_reverse_any(adns_state ads,
|
||||
const struct sockaddr *addr,
|
||||
const char *rzone,
|
||||
adns_rrtype type,
|
||||
adns_queryflags flags,
|
||||
void *context,
|
||||
adns_query *query_r);
|
||||
/* For RBL-style reverse `zone's; look up
|
||||
* <reversed-address>.<zone>
|
||||
* Any type is allowed. _qf_search is ignored.
|
||||
* addr->sa_family must be AF_INET or you get ENOSYS.
|
||||
*/
|
||||
|
||||
ADNS_API void adns_finish(adns_state ads);
|
||||
/* You may call this even if you have queries outstanding;
|
||||
* they will be cancelled.
|
||||
*/
|
||||
|
||||
|
||||
ADNS_API void adns_forallqueries_begin(adns_state ads);
|
||||
ADNS_API adns_query adns_forallqueries_next(adns_state ads, void **context_r);
|
||||
/* Iterator functions, which you can use to loop over the outstanding
|
||||
* (submitted but not yet successfuly checked/waited) queries.
|
||||
*
|
||||
* You can only have one iteration going at once. You may call _begin
|
||||
* at any time; after that, an iteration will be in progress. You may
|
||||
* only call _next when an iteration is in progress - anything else
|
||||
* may coredump. The iteration remains in progress until _next
|
||||
* returns 0, indicating that all the queries have been walked over,
|
||||
* or ANY other adns function is called with the same adns_state (or a
|
||||
* query in the same adns_state). There is no need to explicitly
|
||||
* finish an iteration.
|
||||
*
|
||||
* context_r may be 0. *context_r may not be set when _next returns 0.
|
||||
*/
|
||||
|
||||
ADNS_API void adns_checkconsistency(adns_state ads, adns_query qu);
|
||||
/* Checks the consistency of adns's internal data structures.
|
||||
* If any error is found, the program will abort().
|
||||
* You may pass 0 for qu; if you pass non-null then additional checks
|
||||
* are done to make sure that qu is a valid query.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Example expected/legal calling sequence for submit/check/wait:
|
||||
* adns_init
|
||||
* adns_submit 1
|
||||
* adns_submit 2
|
||||
* adns_submit 3
|
||||
* adns_wait 1
|
||||
* adns_check 3 -> EAGAIN
|
||||
* adns_wait 2
|
||||
* adns_wait 3
|
||||
* ....
|
||||
* adns_finish
|
||||
*/
|
||||
|
||||
/*
|
||||
* Entrypoints for generic asynch io:
|
||||
* (these entrypoints are not very useful except in combination with *
|
||||
* some of the other I/O model calls which can tell you which fds to
|
||||
* be interested in):
|
||||
*
|
||||
* Note that any adns call may cause adns to open and close fds, so
|
||||
* you must call beforeselect or beforepoll again just before
|
||||
* blocking, or you may not have an up-to-date list of it's fds.
|
||||
*/
|
||||
|
||||
ADNS_API int adns_processany(adns_state ads);
|
||||
/* Gives adns flow-of-control for a bit. This will never block, and
|
||||
* can be used with any threading/asynch-io model. If some error
|
||||
* occurred which might cause an event loop to spin then the errno
|
||||
* value is returned.
|
||||
*/
|
||||
|
||||
ADNS_API int adns_processreadable(adns_state ads, ADNS_SOCKET fd, const struct timeval *now);
|
||||
ADNS_API int adns_processwriteable(adns_state ads, ADNS_SOCKET fd, const struct timeval *now);
|
||||
ADNS_API int adns_processexceptional(adns_state ads, ADNS_SOCKET fd, const struct timeval *now);
|
||||
/* Gives adns flow-of-control so that it can process incoming data
|
||||
* from, or send outgoing data via, fd. Very like _processany. If it
|
||||
* returns zero then fd will no longer be readable or writeable
|
||||
* (unless of course more data has arrived since). adns will _only_
|
||||
* use that fd and only in the manner specified, regardless of whether
|
||||
* adns_if_noautosys was specified.
|
||||
*
|
||||
* adns_processexceptional should be called when select(2) reports an
|
||||
* exceptional condition, or poll(2) reports POLLPRI.
|
||||
*
|
||||
* It is fine to call _processreabable or _processwriteable when the
|
||||
* fd is not ready, or with an fd that doesn't belong to adns; it will
|
||||
* then just return 0.
|
||||
*
|
||||
* If some error occurred which might prevent an event loop to spin
|
||||
* then the errno value is returned.
|
||||
*/
|
||||
|
||||
ADNS_API void adns_processtimeouts(adns_state ads, const struct timeval *now);
|
||||
/* Gives adns flow-of-control so that it can process any timeouts
|
||||
* which might have happened. Very like _processreadable/writeable.
|
||||
*
|
||||
* now may be 0; if it isn't, *now must be the current time, recently
|
||||
* obtained from gettimeofday.
|
||||
*/
|
||||
|
||||
ADNS_API void adns_firsttimeout(adns_state ads,
|
||||
struct timeval **tv_mod, struct timeval *tv_buf,
|
||||
struct timeval now);
|
||||
/* Asks adns when it would first like the opportunity to time
|
||||
* something out. now must be the current time, from gettimeofday.
|
||||
*
|
||||
* If tv_mod points to 0 then tv_buf must be non-null, and
|
||||
* _firsttimeout will fill in *tv_buf with the time until the first
|
||||
* timeout, and make *tv_mod point to tv_buf. If adns doesn't have
|
||||
* anything that might need timing out it will leave *tv_mod as 0.
|
||||
*
|
||||
* If *tv_mod is not 0 then tv_buf is not used. adns will update
|
||||
* *tv_mod if it has any earlier timeout, and leave it alone if it
|
||||
* doesn't.
|
||||
*
|
||||
* This call will not actually do any I/O, or change the fds that adns
|
||||
* is using. It always succeeds and never blocks.
|
||||
*/
|
||||
|
||||
ADNS_API void adns_globalsystemfailure(adns_state ads);
|
||||
/* If serious problem(s) happen which globally affect your ability to
|
||||
* interact properly with adns, or adns's ability to function
|
||||
* properly, you or adns can call this function.
|
||||
*
|
||||
* All currently outstanding queries will be made to fail with
|
||||
* adns_s_systemfail, and adns will close any stream sockets it has
|
||||
* open.
|
||||
*
|
||||
* This is used by adns, for example, if gettimeofday() fails.
|
||||
* Without this the program's event loop might start to spin !
|
||||
*
|
||||
* This call will never block.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Entrypoints for select-loop based asynch io:
|
||||
*/
|
||||
|
||||
ADNS_API void adns_beforeselect(adns_state ads, int *maxfd, fd_set *readfds,
|
||||
fd_set *writefds, fd_set *exceptfds,
|
||||
struct timeval **tv_mod, struct timeval *tv_buf,
|
||||
const struct timeval *now);
|
||||
/* Find out file descriptors adns is interested in, and when it would
|
||||
* like the opportunity to time something out. If you do not plan to
|
||||
* block then tv_mod may be 0. Otherwise, tv_mod and tv_buf are as
|
||||
* for adns_firsttimeout. readfds, writefds, exceptfds and maxfd_io may
|
||||
* not be 0.
|
||||
*
|
||||
* If now is not 0 then this will never actually do any I/O, or change
|
||||
* the fds that adns is using or the timeouts it wants. In any case
|
||||
* it won't block, and it will set the timeout to zero if a query
|
||||
* finishes in _beforeselect.
|
||||
*/
|
||||
|
||||
ADNS_API void adns_afterselect(adns_state ads, int maxfd, const fd_set *readfds,
|
||||
const fd_set *writefds, const fd_set *exceptfds,
|
||||
const struct timeval *now);
|
||||
/* Gives adns flow-of-control for a bit; intended for use after
|
||||
* select. This is just a fancy way of calling adns_processreadable/
|
||||
* writeable/timeouts as appropriate, as if select had returned the
|
||||
* data being passed. Always succeeds.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Example calling sequence:
|
||||
*
|
||||
* adns_init _noautosys
|
||||
* loop {
|
||||
* adns_beforeselect
|
||||
* select
|
||||
* adns_afterselect
|
||||
* ...
|
||||
* adns_submit / adns_check
|
||||
* ...
|
||||
* }
|
||||
*/
|
||||
|
||||
/*
|
||||
* Entrypoints for poll-loop based asynch io:
|
||||
*/
|
||||
|
||||
struct pollfd;
|
||||
/* In case your system doesn't have it or you forgot to include
|
||||
* <sys/poll.h>, to stop the following declarations from causing
|
||||
* problems. If your system doesn't have poll then the following
|
||||
* entrypoints will not be defined in libadns. Sorry !
|
||||
*/
|
||||
|
||||
ADNS_API int adns_beforepoll(adns_state ads, struct pollfd *fds, int *nfds_io, int *timeout_io,
|
||||
const struct timeval *now);
|
||||
/* Finds out which fd's adns is interested in, and when it would like
|
||||
* to be able to time things out. This is in a form suitable for use
|
||||
* with poll(2).
|
||||
*
|
||||
* On entry, usually fds should point to at least *nfds_io structs.
|
||||
* adns will fill up to that many structs will information for poll,
|
||||
* and record in *nfds_io how many structs it filled. If it wants to
|
||||
* listen for more structs then *nfds_io will be set to the number
|
||||
* required and _beforepoll will return ERANGE.
|
||||
*
|
||||
* You may call _beforepoll with fds==0 and *nfds_io 0, in which case
|
||||
* adns will fill in the number of fds that it might be interested in
|
||||
* in *nfds_io, and always return either 0 (if it is not interested in
|
||||
* any fds) or ERANGE (if it is).
|
||||
*
|
||||
* NOTE that (unless now is 0) adns may acquire additional fds
|
||||
* from one call to the next, so you must put adns_beforepoll in a
|
||||
* loop, rather than assuming that the second call (with the buffer
|
||||
* size requested by the first) will not return ERANGE.
|
||||
*
|
||||
* adns only ever sets POLLIN, POLLOUT and POLLPRI in its pollfd
|
||||
* structs, and only ever looks at those bits. POLLPRI is required to
|
||||
* detect TCP Urgent Data (which should not be used by a DNS server)
|
||||
* so that adns can know that the TCP stream is now useless.
|
||||
*
|
||||
* In any case, *timeout_io should be a timeout value as for poll(2),
|
||||
* which adns will modify downwards as required. If the caller does
|
||||
* not plan to block then *timeout_io should be 0 on entry, or
|
||||
* alternatively, timeout_io may be 0. (Alternatively, the caller may
|
||||
* use _beforeselect with timeout_io==0 to find out about file
|
||||
* descriptors, and use _firsttimeout is used to find out when adns
|
||||
* might want to time something out.)
|
||||
*
|
||||
* adns_beforepoll will return 0 on success, and will not fail for any
|
||||
* reason other than the fds buffer being too small (ERANGE).
|
||||
*
|
||||
* This call will never actually do any I/O. If you supply the
|
||||
* current time it will not change the fds that adns is using or the
|
||||
* timeouts it wants.
|
||||
*
|
||||
* In any case this call won't block.
|
||||
*/
|
||||
|
||||
#define ADNS_POLLFDS_RECOMMENDED 2
|
||||
/* If you allocate an fds buf with at least RECOMMENDED entries then
|
||||
* you are unlikely to need to enlarge it. You are recommended to do
|
||||
* so if it's convenient. However, you must be prepared for adns to
|
||||
* require more space than this.
|
||||
*/
|
||||
|
||||
ADNS_API void adns_afterpoll(adns_state ads, const struct pollfd *fds, int nfds,
|
||||
const struct timeval *now);
|
||||
/* Gives adns flow-of-control for a bit; intended for use after
|
||||
* poll(2). fds and nfds should be the results from poll(). pollfd
|
||||
* structs mentioning fds not belonging to adns will be ignored.
|
||||
*/
|
||||
|
||||
|
||||
ADNS_API adns_status adns_rr_info(adns_rrtype type,
|
||||
const char **rrtname_r, const char **fmtname_r,
|
||||
int *len_r,
|
||||
const void *datap, char **data_r);
|
||||
/*
|
||||
* Get information about a query type, or convert reply data to a
|
||||
* textual form. type must be specified, and the official name of the
|
||||
* corresponding RR type will be returned in *rrtname_r, and
|
||||
* information about the processing style in *fmtname_r. The length
|
||||
* of the table entry in an answer for that type will be returned in
|
||||
* in *len_r. Any or all of rrtname_r, fmtname_r and len_r may be 0.
|
||||
* If fmtname_r is non-null then *fmtname_r may be null on return,
|
||||
* indicating that no special processing is involved.
|
||||
*
|
||||
* data_r be must be non-null iff datap is. In this case *data_r will
|
||||
* be set to point to a string pointing to a representation of the RR
|
||||
* data in master file format. (The owner name, timeout, class and
|
||||
* type will not be present - only the data part of the RR.) The
|
||||
* memory will have been obtained from malloc() and must be freed by
|
||||
* the caller.
|
||||
*
|
||||
* Usually this routine will succeed. Possible errors include:
|
||||
* adns_s_nomemory
|
||||
* adns_s_rrtypeunknown
|
||||
* adns_s_invaliddata (*datap contained garbage)
|
||||
* If an error occurs then no memory has been allocated,
|
||||
* and *rrtname_r, *fmtname_r, *len_r and *data_r are undefined.
|
||||
*
|
||||
* There are some adns-invented data formats which are not official
|
||||
* master file formats. These include:
|
||||
*
|
||||
* Mailboxes if __qtf_mail822: these are just included as-is.
|
||||
*
|
||||
* Addresses (adns_rr_addr): these may be of pretty much any type.
|
||||
* The representation is in two parts: first, a word for the address
|
||||
* family (ie, in AF_XXX, the XXX), and then one or more items for the
|
||||
* address itself, depending on the format. For an IPv4 address the
|
||||
* syntax is INET followed by the dotted quad (from inet_ntoa).
|
||||
* Currently only IPv4 is supported.
|
||||
*
|
||||
* Text strings (as in adns_rr_txt) appear inside double quotes, and
|
||||
* use \" and \\ to represent " and \, and \xHH to represent
|
||||
* characters not in the range 32-126.
|
||||
*
|
||||
* Hostname with addresses (adns_rr_hostaddr): this consists of the
|
||||
* hostname, as usual, followed by the adns_status value, as an
|
||||
* abbreviation, and then a descriptive string (encoded as if it were
|
||||
* a piece of text), for the address lookup, followed by zero or more
|
||||
* addresses enclosed in ( and ). If the result was a temporary
|
||||
* failure, then a single ? appears instead of the ( ). If the
|
||||
* result was a permanent failure then an empty pair of parentheses
|
||||
* appears (which a space in between). For example, one of the NS
|
||||
* records for greenend.org.uk comes out like
|
||||
* ns.chiark.greenend.org.uk ok "OK" ( INET 195.224.76.132 )
|
||||
* an MX referring to a nonexistent host might come out like:
|
||||
* 50 sun2.nsfnet-relay.ac.uk nxdomain "No such domain" ( )
|
||||
* and if nameserver information is not available you might get:
|
||||
* dns2.spong.dyn.ml.org timeout "DNS query timed out" ?
|
||||
*/
|
||||
|
||||
ADNS_API const char *adns_strerror(adns_status st);
|
||||
ADNS_API const char *adns_errabbrev(adns_status st);
|
||||
ADNS_API const char *adns_errtypeabbrev(adns_status st);
|
||||
/* Like strerror but for adns_status values. adns_errabbrev returns
|
||||
* the abbreviation of the error - eg, for adns_s_timeout it returns
|
||||
* "timeout". adns_errtypeabbrev returns the abbreviation of the
|
||||
* error class: ie, for values up to adns_s_max_XXX it will return the
|
||||
* string XXX. You MUST NOT call these functions with status values
|
||||
* not returned by the same adns library.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,25 @@
|
||||
# src/adns.make - library definitions, including list of object files
|
||||
#
|
||||
# This file is
|
||||
# Copyright (C) 1997-1999 Ian Jackson <[email protected]>
|
||||
#
|
||||
# It is part of adns, which is
|
||||
# Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
# Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
LIBOBJS= types.o event.o query.o reply.o general.o setup.o transmit.o \
|
||||
parse.o poll.o check.o
|
||||
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* check.c
|
||||
* - consistency checks
|
||||
*/
|
||||
/*
|
||||
* This file is
|
||||
* Copyright (C) 1997-1999 Ian Jackson <[email protected]>
|
||||
*
|
||||
* It is part of adns, which is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
* Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
void adns_checkconsistency(adns_state ads, adns_query qu) {
|
||||
adns__consistency(ads,qu,cc_user);
|
||||
}
|
||||
|
||||
/* The original macro. Too gnuish for other compilers */
|
||||
#if 0
|
||||
#define DLIST_CHECK(list, nodevar, part, body) \
|
||||
if ((list).head) { \
|
||||
assert(! (list).head->part back); \
|
||||
for ((nodevar)= (list).head; (nodevar); (nodevar)= (nodevar)->part next) { \
|
||||
assert((nodevar)->part next \
|
||||
? (nodevar) == (nodevar)->part next->part back \
|
||||
: (nodevar) == (list).tail); \
|
||||
body \
|
||||
} \
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
#define DLIST_CHECK1(list, nodevar, body) \
|
||||
if ((list).head) { \
|
||||
assert(! (list).head->back); \
|
||||
for ((nodevar)= (list).head; (nodevar); (nodevar)= (nodevar)->next) { \
|
||||
assert((nodevar)->next \
|
||||
? (nodevar) == (nodevar)->next->back \
|
||||
: (nodevar) == (list).tail); \
|
||||
body \
|
||||
} \
|
||||
}
|
||||
|
||||
#define DLIST_CHECK2(list, nodevar, part, body) \
|
||||
if ((list).head) { \
|
||||
assert(! (list).head->part.back); \
|
||||
for ((nodevar)= (list).head; (nodevar); (nodevar)= (nodevar)->part.next) { \
|
||||
assert((nodevar)->part.next \
|
||||
? (nodevar) == (nodevar)->part.next->part.back \
|
||||
: (nodevar) == (list).tail); \
|
||||
body \
|
||||
} \
|
||||
}
|
||||
|
||||
#define DLIST_ASSERTON(node, nodevar, list, part) \
|
||||
do { \
|
||||
for ((nodevar)= (list).head; \
|
||||
(nodevar) != (node); \
|
||||
(nodevar)= (nodevar)->part next) { \
|
||||
assert((nodevar)); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
static void checkc_query_alloc(adns_state ads, adns_query qu) {
|
||||
allocnode *an;
|
||||
|
||||
|
||||
DLIST_CHECK1(qu->allocations, an, {
|
||||
});
|
||||
}
|
||||
|
||||
static void checkc_query(adns_state ads, adns_query qu) {
|
||||
adns_query child;
|
||||
|
||||
assert(qu->udpnextserver < ads->nservers);
|
||||
assert(!(qu->udpsent & (~0UL << ads->nservers)));
|
||||
assert(qu->search_pos <= ads->nsearchlist);
|
||||
if (qu->parent) DLIST_ASSERTON(qu, child, qu->parent->children, siblings.);
|
||||
}
|
||||
|
||||
static void checkc_notcpbuf(adns_state ads) {
|
||||
assert(!ads->tcpsend.used);
|
||||
assert(!ads->tcprecv.used);
|
||||
assert(!ads->tcprecv_skip);
|
||||
}
|
||||
|
||||
static void checkc_global(adns_state ads) {
|
||||
int i;
|
||||
|
||||
assert(ads->udpsocket >= 0);
|
||||
|
||||
for (i=0; i<ads->nsortlist; i++)
|
||||
assert(!(ads->sortlist[i].base.s_addr & ~ads->sortlist[i].mask.s_addr));
|
||||
|
||||
assert(ads->tcpserver >= 0 && ads->tcpserver < ads->nservers);
|
||||
|
||||
switch (ads->tcpstate) {
|
||||
case server_connecting:
|
||||
assert(ads->tcpsocket >= 0);
|
||||
checkc_notcpbuf(ads);
|
||||
break;
|
||||
case server_disconnected:
|
||||
case server_broken:
|
||||
assert(ads->tcpsocket == -1);
|
||||
checkc_notcpbuf(ads);
|
||||
break;
|
||||
case server_ok:
|
||||
assert(ads->tcpsocket >= 0);
|
||||
assert(ads->tcprecv_skip <= ads->tcprecv.used);
|
||||
break;
|
||||
default:
|
||||
assert(!"ads->tcpstate value");
|
||||
}
|
||||
|
||||
assert(ads->searchlist || !ads->nsearchlist);
|
||||
}
|
||||
|
||||
static void checkc_queue_udpw(adns_state ads) {
|
||||
adns_query qu;
|
||||
|
||||
DLIST_CHECK1(ads->udpw, qu, {
|
||||
assert(qu->state==query_tosend);
|
||||
assert(qu->retries <= UDPMAXRETRIES);
|
||||
assert(qu->udpsent);
|
||||
assert(!qu->children.head && !qu->children.tail);
|
||||
checkc_query(ads,qu);
|
||||
checkc_query_alloc(ads,qu);
|
||||
});
|
||||
}
|
||||
|
||||
static void checkc_queue_tcpw(adns_state ads) {
|
||||
adns_query qu;
|
||||
|
||||
DLIST_CHECK1(ads->tcpw, qu, {
|
||||
assert(qu->state==query_tcpw);
|
||||
assert(!qu->children.head && !qu->children.tail);
|
||||
assert(qu->retries <= ads->nservers+1);
|
||||
checkc_query(ads,qu);
|
||||
checkc_query_alloc(ads,qu);
|
||||
});
|
||||
}
|
||||
|
||||
static void checkc_queue_childw(adns_state ads) {
|
||||
adns_query parent, child;
|
||||
|
||||
DLIST_CHECK1(ads->childw, parent, {
|
||||
assert(parent->state == query_childw);
|
||||
assert(parent->children.head);
|
||||
DLIST_CHECK2(parent->children, child, siblings, {
|
||||
assert(child->parent == parent);
|
||||
assert(child->state != query_done);
|
||||
});
|
||||
checkc_query(ads,parent);
|
||||
checkc_query_alloc(ads,parent);
|
||||
});
|
||||
}
|
||||
|
||||
static void checkc_queue_output(adns_state ads) {
|
||||
adns_query qu;
|
||||
|
||||
DLIST_CHECK1(ads->output, qu, {
|
||||
assert(qu->state == query_done);
|
||||
assert(!qu->children.head && !qu->children.tail);
|
||||
assert(!qu->parent);
|
||||
assert(!qu->allocations.head && !qu->allocations.tail);
|
||||
checkc_query(ads,qu);
|
||||
});
|
||||
}
|
||||
|
||||
void adns__consistency(adns_state ads, adns_query qu, consistency_checks cc) {
|
||||
adns_query search;
|
||||
|
||||
switch (cc) {
|
||||
case cc_user:
|
||||
break;
|
||||
case cc_entex:
|
||||
if (!(ads->iflags & adns_if_checkc_entex)) return;
|
||||
break;
|
||||
case cc_freq:
|
||||
if ((ads->iflags & adns_if_checkc_freq) != adns_if_checkc_freq) return;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
checkc_global(ads);
|
||||
checkc_queue_udpw(ads);
|
||||
checkc_queue_tcpw(ads);
|
||||
checkc_queue_childw(ads);
|
||||
checkc_queue_output(ads);
|
||||
|
||||
if (qu) {
|
||||
switch (qu->state) {
|
||||
case query_tosend:
|
||||
DLIST_ASSERTON(qu, search, ads->udpw, );
|
||||
break;
|
||||
case query_tcpw:
|
||||
DLIST_ASSERTON(qu, search, ads->tcpw, );
|
||||
break;
|
||||
case query_childw:
|
||||
DLIST_ASSERTON(qu, search, ads->childw, );
|
||||
break;
|
||||
case query_done:
|
||||
DLIST_ASSERTON(qu, search, ads->output, );
|
||||
break;
|
||||
default:
|
||||
assert(!"specific query state");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/* src/config.h. Generated automatically by configure. */
|
||||
/* src/config.h.in. Generated automatically from configure.in by autoheader. */
|
||||
|
||||
/* Define if inline functions a la GCC are available. */
|
||||
#define HAVE_INLINE 1
|
||||
|
||||
/* Define if function attributes a la GCC 2.5 and higher are available. */
|
||||
/* #define HAVE_GNUC25_ATTRIB 1 */
|
||||
|
||||
/* Define if constant functions a la GCC 2.5 and higher are available. */
|
||||
/* #define HAVE_GNUC25_CONST 1 */
|
||||
|
||||
/* Define if nonreturning functions a la GCC 2.5 and higher are available. */
|
||||
/* #define HAVE_GNUC25_NORETURN 1 */
|
||||
|
||||
/* Define if printf-format argument lists a la GCC are available. */
|
||||
/* #define HAVE_GNUC25_PRINTFFORMAT 1 */
|
||||
|
||||
/* Define if we want to include rpc/types.h. Crap BSDs put INADDR_LOOPBACK there. */
|
||||
/* #undef HAVEUSE_RPCTYPES_H */
|
||||
|
||||
/* Define if you have the poll function. */
|
||||
/* #define HAVE_POLL 1 */
|
||||
|
||||
/* Define if you have the <sys/select.h> header file. */
|
||||
#define HAVE_SYS_SELECT_H 1
|
||||
|
||||
/* Define if you have the nsl library (-lnsl). */
|
||||
/* #undef HAVE_LIBNSL */
|
||||
|
||||
/* Define if you have the socket library (-lsocket). */
|
||||
/* #undef HAVE_LIBSOCKET */
|
||||
|
||||
/* Use the definitions: */
|
||||
|
||||
#ifndef HAVE_INLINE
|
||||
#define inline
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POLL
|
||||
#include <sys/poll.h>
|
||||
#else
|
||||
/* kludge it up */
|
||||
struct pollfd { int fd; short events; short revents; };
|
||||
#define POLLIN 1
|
||||
#define POLLPRI 2
|
||||
#define POLLOUT 4
|
||||
#endif
|
||||
|
||||
/* GNU C attributes. */
|
||||
#ifndef FUNCATTR
|
||||
#ifdef HAVE_GNUC25_ATTRIB
|
||||
#define FUNCATTR(x) __attribute__(x)
|
||||
#else
|
||||
#define FUNCATTR(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* GNU C printf formats, or null. */
|
||||
#ifndef ATTRPRINTF
|
||||
#ifdef HAVE_GNUC25_PRINTFFORMAT
|
||||
#define ATTRPRINTF(si,tc) format(printf,si,tc)
|
||||
#else
|
||||
#define ATTRPRINTF(si,tc)
|
||||
#endif
|
||||
#endif
|
||||
#ifndef PRINTFFORMAT
|
||||
#define PRINTFFORMAT(si,tc) FUNCATTR((ATTRPRINTF(si,tc)))
|
||||
#endif
|
||||
|
||||
/* GNU C nonreturning functions, or null. */
|
||||
#ifndef ATTRNORETURN
|
||||
#ifdef HAVE_GNUC25_NORETURN
|
||||
#define ATTRNORETURN noreturn
|
||||
#else
|
||||
#define ATTRNORETURN
|
||||
#endif
|
||||
#endif
|
||||
#ifndef NONRETURNING
|
||||
#define NONRETURNING FUNCATTR((ATTRNORETURN))
|
||||
#endif
|
||||
|
||||
/* Combination of both the above. */
|
||||
#ifndef NONRETURNPRINTFFORMAT
|
||||
#define NONRETURNPRINTFFORMAT(si,tc) FUNCATTR((ATTRPRINTF(si,tc),ATTRNORETURN))
|
||||
#endif
|
||||
|
||||
/* GNU C constant functions, or null. */
|
||||
#ifndef ATTRCONST
|
||||
#ifdef HAVE_GNUC25_CONST
|
||||
#define ATTRCONST const
|
||||
#else
|
||||
#define ATTRCONST
|
||||
#endif
|
||||
#endif
|
||||
#ifndef CONSTANT
|
||||
#define CONSTANT FUNCATTR((ATTRCONST))
|
||||
#endif
|
||||
|
||||
#ifdef HAVEUSE_RPCTYPES_H
|
||||
#include <rpc/types.h>
|
||||
#endif
|
||||
|
||||
#if !defined(ADNS_JGAA_WIN32) && defined(HAVE_SYS_SELECT_H)
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
@@ -0,0 +1,105 @@
|
||||
/* src/config.h.in. Generated automatically from configure.in by autoheader. */
|
||||
|
||||
/* Define if inline functions a la GCC are available. */
|
||||
#undef HAVE_INLINE
|
||||
|
||||
/* Define if function attributes a la GCC 2.5 and higher are available. */
|
||||
#undef HAVE_GNUC25_ATTRIB
|
||||
|
||||
/* Define if constant functions a la GCC 2.5 and higher are available. */
|
||||
#undef HAVE_GNUC25_CONST
|
||||
|
||||
/* Define if nonreturning functions a la GCC 2.5 and higher are available. */
|
||||
#undef HAVE_GNUC25_NORETURN
|
||||
|
||||
/* Define if printf-format argument lists a la GCC are available. */
|
||||
#undef HAVE_GNUC25_PRINTFFORMAT
|
||||
|
||||
/* Define if we want to include rpc/types.h. Crap BSDs put INADDR_LOOPBACK there. */
|
||||
#undef HAVEUSE_RPCTYPES_H
|
||||
|
||||
/* Define if you have the poll function. */
|
||||
#undef HAVE_POLL
|
||||
|
||||
/* Define if you have the <sys/select.h> header file. */
|
||||
#undef HAVE_SYS_SELECT_H
|
||||
|
||||
/* Define if you have the nsl library (-lnsl). */
|
||||
#undef HAVE_LIBNSL
|
||||
|
||||
/* Define if you have the socket library (-lsocket). */
|
||||
#undef HAVE_LIBSOCKET
|
||||
|
||||
/* Use the definitions: */
|
||||
|
||||
#ifndef HAVE_INLINE
|
||||
#define inline
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POLL
|
||||
#include <sys/poll.h>
|
||||
#else
|
||||
/* kludge it up */
|
||||
struct pollfd { int fd; short events; short revents; };
|
||||
#define POLLIN 1
|
||||
#define POLLPRI 2
|
||||
#define POLLOUT 4
|
||||
#endif
|
||||
|
||||
/* GNU C attributes. */
|
||||
#ifndef FUNCATTR
|
||||
#ifdef HAVE_GNUC25_ATTRIB
|
||||
#define FUNCATTR(x) __attribute__(x)
|
||||
#else
|
||||
#define FUNCATTR(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* GNU C printf formats, or null. */
|
||||
#ifndef ATTRPRINTF
|
||||
#ifdef HAVE_GNUC25_PRINTFFORMAT
|
||||
#define ATTRPRINTF(si,tc) format(printf,si,tc)
|
||||
#else
|
||||
#define ATTRPRINTF(si,tc)
|
||||
#endif
|
||||
#endif
|
||||
#ifndef PRINTFFORMAT
|
||||
#define PRINTFFORMAT(si,tc) FUNCATTR((ATTRPRINTF(si,tc)))
|
||||
#endif
|
||||
|
||||
/* GNU C nonreturning functions, or null. */
|
||||
#ifndef ATTRNORETURN
|
||||
#ifdef HAVE_GNUC25_NORETURN
|
||||
#define ATTRNORETURN noreturn
|
||||
#else
|
||||
#define ATTRNORETURN
|
||||
#endif
|
||||
#endif
|
||||
#ifndef NONRETURNING
|
||||
#define NONRETURNING FUNCATTR((ATTRNORETURN))
|
||||
#endif
|
||||
|
||||
/* Combination of both the above. */
|
||||
#ifndef NONRETURNPRINTFFORMAT
|
||||
#define NONRETURNPRINTFFORMAT(si,tc) FUNCATTR((ATTRPRINTF(si,tc),ATTRNORETURN))
|
||||
#endif
|
||||
|
||||
/* GNU C constant functions, or null. */
|
||||
#ifndef ATTRCONST
|
||||
#ifdef HAVE_GNUC25_CONST
|
||||
#define ATTRCONST const
|
||||
#else
|
||||
#define ATTRCONST
|
||||
#endif
|
||||
#endif
|
||||
#ifndef CONSTANT
|
||||
#define CONSTANT FUNCATTR((ATTRCONST))
|
||||
#endif
|
||||
|
||||
#ifdef HAVEUSE_RPCTYPES_H
|
||||
#include <rpc/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* dlist.h
|
||||
* - macros for handling doubly linked lists
|
||||
*/
|
||||
/*
|
||||
* This file is
|
||||
* Copyright (C) 1997-1999 Ian Jackson <[email protected]>
|
||||
*
|
||||
* It is part of adns, which is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
* Copyright (C) 1999 Tony Finch <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef ADNS_DLIST_H_INCLUDED
|
||||
#define ADNS_DLIST_H_INCLUDED
|
||||
|
||||
#define LIST_INIT(list) ((list).head= (list).tail= 0)
|
||||
#define LINK_INIT(link) ((link).next= (link).back= 0)
|
||||
|
||||
#define LIST_UNLINK_PART(list,node,part) \
|
||||
do { \
|
||||
if ((node)->part back) (node)->part back->part next= (node)->part next; \
|
||||
else (list).head= (node)->part next; \
|
||||
if ((node)->part next) (node)->part next->part back= (node)->part back; \
|
||||
else (list).tail= (node)->part back; \
|
||||
} while(0)
|
||||
|
||||
#define LIST_LINK_TAIL_PART(list,node,part) \
|
||||
do { \
|
||||
(node)->part next= 0; \
|
||||
(node)->part back= (list).tail; \
|
||||
if ((list).tail) (list).tail->part next= (node); else (list).head= (node); \
|
||||
(list).tail= (node); \
|
||||
} while(0)
|
||||
|
||||
#define LIST_UNLINK(list,node) LIST_UNLINK_PART(list,node,)
|
||||
#define LIST_LINK_TAIL(list,node) LIST_LINK_TAIL_PART(list,node,)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,743 @@
|
||||
/*
|
||||
* event.c
|
||||
* - event loop core
|
||||
* - TCP connection management
|
||||
* - user-visible check/wait and event-loop-related functions
|
||||
*/
|
||||
/*
|
||||
* This file is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
*
|
||||
* It is part of adns, which is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
* Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, adns_socket_write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
# include "adns_win32.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef ADNS_JGAA_WIN32
|
||||
#else
|
||||
# include <unistd.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/time.h>
|
||||
# include <netdb.h>
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include "internal.h"
|
||||
#include "tvarith.h"
|
||||
|
||||
/* TCP connection management. */
|
||||
|
||||
static void tcp_close(adns_state ads) {
|
||||
int serv;
|
||||
|
||||
serv= ads->tcpserver;
|
||||
adns_socket_close(ads->tcpsocket);
|
||||
ads->tcpsocket= -1;
|
||||
ads->tcprecv.used= ads->tcprecv_skip= ads->tcpsend.used= 0;
|
||||
}
|
||||
|
||||
void adns__tcp_broken(adns_state ads, const char *what, const char *why) {
|
||||
int serv;
|
||||
adns_query qu;
|
||||
|
||||
assert(ads->tcpstate == server_connecting || ads->tcpstate == server_ok);
|
||||
serv= ads->tcpserver;
|
||||
if (what) adns__warn(ads,serv,0,"TCP connection failed: %s: %s",what,why);
|
||||
|
||||
if (ads->tcpstate == server_connecting) {
|
||||
/* Counts as a retry for all the queries waiting for TCP. */
|
||||
for (qu= ads->tcpw.head; qu; qu= qu->next)
|
||||
qu->retries++;
|
||||
}
|
||||
|
||||
tcp_close(ads);
|
||||
ads->tcpstate= server_broken;
|
||||
ads->tcpserver= (serv+1)%ads->nservers;
|
||||
}
|
||||
|
||||
static void tcp_connected(adns_state ads, struct timeval now) {
|
||||
adns_query qu, nqu;
|
||||
|
||||
adns__debug(ads,ads->tcpserver,0,"TCP connected");
|
||||
ads->tcpstate= server_ok;
|
||||
for (qu= ads->tcpw.head; qu && ads->tcpstate == server_ok; qu= nqu) {
|
||||
nqu= qu->next;
|
||||
assert(qu->state == query_tcpw);
|
||||
adns__querysend_tcp(qu,now);
|
||||
}
|
||||
}
|
||||
|
||||
void adns__tcp_tryconnect(adns_state ads, struct timeval now) {
|
||||
int r, tries;
|
||||
ADNS_SOCKET fd;
|
||||
struct sockaddr_in addr;
|
||||
struct protoent *proto;
|
||||
|
||||
for (tries=0; tries<ads->nservers; tries++) {
|
||||
switch (ads->tcpstate) {
|
||||
case server_connecting:
|
||||
case server_ok:
|
||||
case server_broken:
|
||||
return;
|
||||
case server_disconnected:
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
assert(!ads->tcpsend.used);
|
||||
assert(!ads->tcprecv.used);
|
||||
assert(!ads->tcprecv_skip);
|
||||
|
||||
proto= getprotobyname("tcp");
|
||||
if (!proto) { adns__diag(ads,-1,0,"unable to find protocol no. for TCP !"); return; }
|
||||
ADNS_CLEAR_ERRNO
|
||||
fd= socket(AF_INET,SOCK_STREAM,proto->p_proto);
|
||||
ADNS_CAPTURE_ERRNO;
|
||||
if (fd<0) {
|
||||
adns__diag(ads,-1,0,"cannot create TCP socket: %s",strerror(errno));
|
||||
return;
|
||||
}
|
||||
r= adns__setnonblock(ads,fd);
|
||||
if (r) {
|
||||
adns__diag(ads,-1,0,"cannot make TCP socket nonblocking: %s",strerror(r));
|
||||
adns_socket_close(fd);
|
||||
return;
|
||||
}
|
||||
memset(&addr,0,sizeof(addr));
|
||||
addr.sin_family= AF_INET;
|
||||
addr.sin_port= htons(DNS_PORT);
|
||||
addr.sin_addr= ads->servers[ads->tcpserver].addr;
|
||||
r= connect(fd,(const struct sockaddr*)&addr,sizeof(addr));
|
||||
ads->tcpsocket= fd;
|
||||
ads->tcpstate= server_connecting;
|
||||
if (r==0) { tcp_connected(ads,now); return; }
|
||||
if (errno == EWOULDBLOCK || errno == EINPROGRESS) {
|
||||
ads->tcptimeout= now;
|
||||
timevaladd(&ads->tcptimeout,TCPCONNMS);
|
||||
return;
|
||||
}
|
||||
adns__tcp_broken(ads,"connect",strerror(errno));
|
||||
ads->tcpstate= server_disconnected;
|
||||
}
|
||||
}
|
||||
|
||||
/* Timeout handling functions. */
|
||||
|
||||
void adns__must_gettimeofday(adns_state ads, const struct timeval **now_io,
|
||||
struct timeval *tv_buf) {
|
||||
const struct timeval *now;
|
||||
int r;
|
||||
|
||||
now= *now_io;
|
||||
if (now) return;
|
||||
r= gettimeofday(tv_buf,0); if (!r) { *now_io= tv_buf; return; }
|
||||
adns__diag(ads,-1,0,"gettimeofday failed: %s",strerror(errno));
|
||||
adns_globalsystemfailure(ads);
|
||||
return;
|
||||
}
|
||||
|
||||
static void inter_immed(struct timeval **tv_io, struct timeval *tvbuf) {
|
||||
struct timeval *rbuf;
|
||||
|
||||
if (!tv_io) return;
|
||||
|
||||
rbuf= *tv_io;
|
||||
if (!rbuf) { *tv_io= rbuf= tvbuf; }
|
||||
|
||||
timerclear(rbuf);
|
||||
}
|
||||
|
||||
static void inter_maxto(struct timeval **tv_io, struct timeval *tvbuf,
|
||||
struct timeval maxto) {
|
||||
struct timeval *rbuf;
|
||||
|
||||
if (!tv_io) return;
|
||||
rbuf= *tv_io;
|
||||
if (!rbuf) {
|
||||
*tvbuf= maxto; *tv_io= tvbuf;
|
||||
} else {
|
||||
if (timercmp(rbuf,&maxto,>)) *rbuf= maxto;
|
||||
}
|
||||
/*fprintf(stderr,"inter_maxto maxto=%ld.%06ld result=%ld.%06ld\n",
|
||||
maxto.tv_sec,maxto.tv_usec,(**tv_io).tv_sec,(**tv_io).tv_usec);*/
|
||||
}
|
||||
|
||||
static void inter_maxtoabs(struct timeval **tv_io, struct timeval *tvbuf,
|
||||
struct timeval now, struct timeval maxtime) {
|
||||
/* tv_io may be 0 */
|
||||
ldiv_t dr;
|
||||
|
||||
/*fprintf(stderr,"inter_maxtoabs now=%ld.%06ld maxtime=%ld.%06ld\n",
|
||||
now.tv_sec,now.tv_usec,maxtime.tv_sec,maxtime.tv_usec);*/
|
||||
if (!tv_io) return;
|
||||
maxtime.tv_sec -= (now.tv_sec+2);
|
||||
maxtime.tv_usec -= (now.tv_usec-2000000);
|
||||
dr= ldiv(maxtime.tv_usec,1000000);
|
||||
maxtime.tv_sec += dr.quot;
|
||||
maxtime.tv_usec -= dr.quot*1000000;
|
||||
if (maxtime.tv_sec<0) timerclear(&maxtime);
|
||||
inter_maxto(tv_io,tvbuf,maxtime);
|
||||
}
|
||||
|
||||
static void timeouts_queue(adns_state ads, int act,
|
||||
struct timeval **tv_io, struct timeval *tvbuf,
|
||||
struct timeval now, struct query_queue *queue) {
|
||||
adns_query qu, nqu;
|
||||
|
||||
for (qu= queue->head; qu; qu= nqu) {
|
||||
nqu= qu->next;
|
||||
if (!timercmp(&now,&qu->timeout,>)) {
|
||||
inter_maxtoabs(tv_io,tvbuf,now,qu->timeout);
|
||||
} else {
|
||||
if (!act) { inter_immed(tv_io,tvbuf); return; }
|
||||
LIST_UNLINK(*queue,qu);
|
||||
if (qu->state != query_tosend) {
|
||||
adns__query_fail(qu,adns_s_timeout);
|
||||
} else {
|
||||
adns__query_send(qu,now);
|
||||
}
|
||||
nqu= queue->head;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void tcp_events(adns_state ads, int act,
|
||||
struct timeval **tv_io, struct timeval *tvbuf,
|
||||
struct timeval now) {
|
||||
adns_query qu, nqu;
|
||||
|
||||
for (;;) {
|
||||
switch (ads->tcpstate) {
|
||||
case server_broken:
|
||||
if (!act) { inter_immed(tv_io,tvbuf); return; }
|
||||
for (qu= ads->tcpw.head; qu; qu= nqu) {
|
||||
nqu= qu->next;
|
||||
assert(qu->state == query_tcpw);
|
||||
if (qu->retries > ads->nservers) {
|
||||
LIST_UNLINK(ads->tcpw,qu);
|
||||
adns__query_fail(qu,adns_s_allservfail);
|
||||
}
|
||||
}
|
||||
ads->tcpstate= server_disconnected;
|
||||
case server_disconnected: /* fall through */
|
||||
if (!ads->tcpw.head) return;
|
||||
if (!act) { inter_immed(tv_io,tvbuf); return; }
|
||||
adns__tcp_tryconnect(ads,now);
|
||||
break;
|
||||
case server_ok:
|
||||
if (ads->tcpw.head) return;
|
||||
if (!ads->tcptimeout.tv_sec) {
|
||||
assert(!ads->tcptimeout.tv_usec);
|
||||
ads->tcptimeout= now;
|
||||
timevaladd(&ads->tcptimeout,TCPIDLEMS);
|
||||
}
|
||||
case server_connecting: /* fall through */
|
||||
if (!act || !timercmp(&now,&ads->tcptimeout,>)) {
|
||||
inter_maxtoabs(tv_io,tvbuf,now,ads->tcptimeout);
|
||||
return;
|
||||
} {
|
||||
/* TCP timeout has happened */
|
||||
switch (ads->tcpstate) {
|
||||
case server_connecting: /* failed to connect */
|
||||
adns__tcp_broken(ads,"unable to make connection","timed out");
|
||||
break;
|
||||
case server_ok: /* idle timeout */
|
||||
tcp_close(ads);
|
||||
ads->tcpstate= server_disconnected;
|
||||
return;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void adns__timeouts(adns_state ads, int act,
|
||||
struct timeval **tv_io, struct timeval *tvbuf,
|
||||
struct timeval now) {
|
||||
timeouts_queue(ads,act,tv_io,tvbuf,now, &ads->udpw);
|
||||
timeouts_queue(ads,act,tv_io,tvbuf,now, &ads->tcpw);
|
||||
tcp_events(ads,act,tv_io,tvbuf,now);
|
||||
}
|
||||
|
||||
void adns_firsttimeout(adns_state ads,
|
||||
struct timeval **tv_io, struct timeval *tvbuf,
|
||||
struct timeval now) {
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
adns__timeouts(ads, 0, tv_io,tvbuf, now);
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
}
|
||||
|
||||
void adns_processtimeouts(adns_state ads, const struct timeval *now) {
|
||||
struct timeval tv_buf;
|
||||
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
adns__must_gettimeofday(ads,&now,&tv_buf);
|
||||
if (now) adns__timeouts(ads, 1, 0,0, *now);
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
}
|
||||
|
||||
/* fd handling functions. These are the top-level of the real work of
|
||||
* reception and often transmission.
|
||||
*/
|
||||
|
||||
int adns__pollfds(adns_state ads, struct pollfd pollfds_buf[MAX_POLLFDS]) {
|
||||
/* Returns the number of entries filled in. Always zeroes revents. */
|
||||
|
||||
assert(MAX_POLLFDS==2);
|
||||
|
||||
pollfds_buf[0].fd= ads->udpsocket;
|
||||
pollfds_buf[0].events= POLLIN;
|
||||
pollfds_buf[0].revents= 0;
|
||||
|
||||
switch (ads->tcpstate) {
|
||||
case server_disconnected:
|
||||
case server_broken:
|
||||
return 1;
|
||||
case server_connecting:
|
||||
pollfds_buf[1].events= POLLOUT;
|
||||
break;
|
||||
case server_ok:
|
||||
pollfds_buf[1].events= ads->tcpsend.used ? POLLIN|POLLOUT|POLLPRI : POLLIN|POLLPRI;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
pollfds_buf[1].fd= ads->tcpsocket;
|
||||
return 2;
|
||||
}
|
||||
|
||||
int adns_processreadable(adns_state ads, ADNS_SOCKET fd, const struct timeval *now) {
|
||||
int want, dgramlen, r, udpaddrlen, serv, old_skip;
|
||||
byte udpbuf[DNS_MAXUDP];
|
||||
struct sockaddr_in udpaddr;
|
||||
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
|
||||
switch (ads->tcpstate) {
|
||||
case server_disconnected:
|
||||
case server_broken:
|
||||
case server_connecting:
|
||||
break;
|
||||
case server_ok:
|
||||
if (fd != ads->tcpsocket) break;
|
||||
assert(!ads->tcprecv_skip);
|
||||
do {
|
||||
if (ads->tcprecv.used >= ads->tcprecv_skip+2) {
|
||||
dgramlen= ((ads->tcprecv.buf[ads->tcprecv_skip]<<8) |
|
||||
ads->tcprecv.buf[ads->tcprecv_skip+1]);
|
||||
if (ads->tcprecv.used >= ads->tcprecv_skip+2+dgramlen) {
|
||||
old_skip= ads->tcprecv_skip;
|
||||
ads->tcprecv_skip += 2+dgramlen;
|
||||
adns__procdgram(ads, ads->tcprecv.buf+old_skip+2,
|
||||
dgramlen, ads->tcpserver, 1,*now);
|
||||
continue;
|
||||
} else {
|
||||
want= 2+dgramlen;
|
||||
}
|
||||
} else {
|
||||
want= 2;
|
||||
}
|
||||
ads->tcprecv.used -= ads->tcprecv_skip;
|
||||
memmove(ads->tcprecv.buf,ads->tcprecv.buf+ads->tcprecv_skip,ads->tcprecv.used);
|
||||
ads->tcprecv_skip= 0;
|
||||
if (!adns__vbuf_ensure(&ads->tcprecv,want)) { r= ENOMEM; goto xit; }
|
||||
assert(ads->tcprecv.used <= ads->tcprecv.avail);
|
||||
if (ads->tcprecv.used == ads->tcprecv.avail) continue;
|
||||
ADNS_CLEAR_ERRNO;
|
||||
r= adns_socket_read(ads->tcpsocket,
|
||||
ads->tcprecv.buf+ads->tcprecv.used,
|
||||
ads->tcprecv.avail-ads->tcprecv.used);
|
||||
ADNS_CAPTURE_ERRNO;
|
||||
if (r>0) {
|
||||
ads->tcprecv.used+= r;
|
||||
} else {
|
||||
if (r) {
|
||||
if (errno==EAGAIN || errno==EWOULDBLOCK) { r= 0; goto xit; }
|
||||
if (errno==EINTR) continue;
|
||||
if (errno_resources(errno)) { r= errno; goto xit; }
|
||||
}
|
||||
adns__tcp_broken(ads,"adns_socket_read",r?strerror(errno):"closed");
|
||||
}
|
||||
} while (ads->tcpstate == server_ok);
|
||||
r= 0; goto xit;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
if (fd == ads->udpsocket) {
|
||||
for (;;) {
|
||||
udpaddrlen= sizeof(udpaddr);
|
||||
ADNS_CLEAR_ERRNO;
|
||||
r= recvfrom(ads->udpsocket,udpbuf,sizeof(udpbuf),0,
|
||||
(struct sockaddr*)&udpaddr,&udpaddrlen);
|
||||
ADNS_CAPTURE_ERRNO;
|
||||
if (r<0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) { r= 0; goto xit; }
|
||||
if (errno == EINTR) continue;
|
||||
if (errno_resources(errno)) { r= errno; goto xit; }
|
||||
adns__warn(ads,-1,0,"datagram receive error: %s",strerror(errno));
|
||||
r= 0; goto xit;
|
||||
}
|
||||
if (udpaddrlen != sizeof(udpaddr)) {
|
||||
adns__diag(ads,-1,0,"datagram received with wrong address length %d"
|
||||
" (expected %lu)", udpaddrlen,
|
||||
(unsigned long)sizeof(udpaddr));
|
||||
continue;
|
||||
}
|
||||
if (udpaddr.sin_family != AF_INET) {
|
||||
adns__diag(ads,-1,0,"datagram received with wrong protocol family"
|
||||
" %u (expected %u)",udpaddr.sin_family,AF_INET);
|
||||
continue;
|
||||
}
|
||||
if (ntohs(udpaddr.sin_port) != DNS_PORT) {
|
||||
adns__diag(ads,-1,0,"datagram received from wrong port %u (expected %u)",
|
||||
ntohs(udpaddr.sin_port),DNS_PORT);
|
||||
continue;
|
||||
}
|
||||
for (serv= 0;
|
||||
serv < ads->nservers &&
|
||||
ads->servers[serv].addr.s_addr != udpaddr.sin_addr.s_addr;
|
||||
serv++);
|
||||
if (serv >= ads->nservers) {
|
||||
adns__warn(ads,-1,0,"datagram received from unknown nameserver %s",
|
||||
inet_ntoa(udpaddr.sin_addr));
|
||||
continue;
|
||||
}
|
||||
adns__procdgram(ads,udpbuf,r,serv,0,*now);
|
||||
}
|
||||
}
|
||||
r= 0;
|
||||
xit:
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
return r;
|
||||
}
|
||||
|
||||
int adns_processwriteable(adns_state ads, ADNS_SOCKET fd, const struct timeval *now) {
|
||||
int r;
|
||||
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
|
||||
switch (ads->tcpstate) {
|
||||
case server_disconnected:
|
||||
case server_broken:
|
||||
break;
|
||||
case server_connecting:
|
||||
if (fd != ads->tcpsocket) break;
|
||||
assert(ads->tcprecv.used==0);
|
||||
assert(ads->tcprecv_skip==0);
|
||||
for (;;) {
|
||||
if (!adns__vbuf_ensure(&ads->tcprecv,1)) { r= ENOMEM; goto xit; }
|
||||
ADNS_CLEAR_ERRNO;
|
||||
r= adns_socket_read(ads->tcpsocket,&ads->tcprecv.buf,1);
|
||||
ADNS_CAPTURE_ERRNO;
|
||||
if (r==0 || (r<0 && (errno==EAGAIN || errno==EWOULDBLOCK))) {
|
||||
tcp_connected(ads,*now);
|
||||
r= 0; goto xit;
|
||||
}
|
||||
if (r>0) {
|
||||
adns__tcp_broken(ads,"connect/adns_socket_read","sent data before first request");
|
||||
r= 0; goto xit;
|
||||
}
|
||||
if (errno==EINTR) continue;
|
||||
if (errno_resources(errno)) { r= errno; goto xit; }
|
||||
adns__tcp_broken(ads,"connect/adns_socket_read",strerror(errno));
|
||||
r= 0; goto xit;
|
||||
} /* not reached */
|
||||
case server_ok:
|
||||
if (fd != ads->tcpsocket) break;
|
||||
while (ads->tcpsend.used) {
|
||||
adns__sigpipe_protect(ads);
|
||||
ADNS_CLEAR_ERRNO;
|
||||
r= adns_socket_write(ads->tcpsocket,ads->tcpsend.buf,ads->tcpsend.used);
|
||||
ADNS_CAPTURE_ERRNO;
|
||||
adns__sigpipe_unprotect(ads);
|
||||
if (r<0) {
|
||||
if (errno==EINTR) continue;
|
||||
if (errno==EAGAIN || errno==EWOULDBLOCK) { r= 0; goto xit; }
|
||||
if (errno_resources(errno)) { r= errno; goto xit; }
|
||||
adns__tcp_broken(ads,"adns_socket_write",strerror(errno));
|
||||
r= 0; goto xit;
|
||||
} else if (r>0) {
|
||||
ads->tcpsend.used -= r;
|
||||
memmove(ads->tcpsend.buf,ads->tcpsend.buf+r,ads->tcpsend.used);
|
||||
}
|
||||
}
|
||||
r= 0;
|
||||
goto xit;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
r= 0;
|
||||
xit:
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
return r;
|
||||
}
|
||||
|
||||
int adns_processexceptional(adns_state ads, ADNS_SOCKET fd, const struct timeval *now) {
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
switch (ads->tcpstate) {
|
||||
case server_disconnected:
|
||||
case server_broken:
|
||||
break;
|
||||
case server_connecting:
|
||||
case server_ok:
|
||||
if (fd != ads->tcpsocket) break;
|
||||
adns__tcp_broken(ads,"poll/select","exceptional condition detected");
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fd_event(adns_state ads, ADNS_SOCKET fd,
|
||||
int revent, int pollflag,
|
||||
int maxfd, const fd_set *fds,
|
||||
int (*func)(adns_state, ADNS_SOCKET fd, const struct timeval *now),
|
||||
struct timeval now, int *r_r) {
|
||||
int r;
|
||||
|
||||
if (!(revent & pollflag)) return;
|
||||
if (fds && !((int)fd<maxfd && FD_ISSET(fd,fds))) return;
|
||||
r= func(ads,fd,&now);
|
||||
if (r) {
|
||||
if (r_r) {
|
||||
*r_r= r;
|
||||
} else {
|
||||
adns__diag(ads,-1,0,"process fd failed after select: %s",strerror(errno));
|
||||
adns_globalsystemfailure(ads);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void adns__fdevents(adns_state ads,
|
||||
const struct pollfd *pollfds, int npollfds,
|
||||
int maxfd, const fd_set *readfds,
|
||||
const fd_set *writefds, const fd_set *exceptfds,
|
||||
struct timeval now, int *r_r) {
|
||||
int i, revents;
|
||||
ADNS_SOCKET fd;
|
||||
|
||||
for (i=0; i<npollfds; i++) {
|
||||
fd= pollfds[i].fd;
|
||||
if ((int)fd >= maxfd) maxfd= fd+1;
|
||||
revents= pollfds[i].revents;
|
||||
fd_event(ads,fd, revents,POLLIN, maxfd,readfds, adns_processreadable,now,r_r);
|
||||
fd_event(ads,fd, revents,POLLOUT, maxfd,writefds, adns_processwriteable,now,r_r);
|
||||
fd_event(ads,fd, revents,POLLPRI, maxfd,exceptfds, adns_processexceptional,now,r_r);
|
||||
}
|
||||
}
|
||||
|
||||
/* Wrappers for select(2). */
|
||||
|
||||
void adns_beforeselect(adns_state ads, int *maxfd_io, fd_set *readfds_io,
|
||||
fd_set *writefds_io, fd_set *exceptfds_io,
|
||||
struct timeval **tv_mod, struct timeval *tv_tobuf,
|
||||
const struct timeval *now) {
|
||||
struct timeval tv_nowbuf;
|
||||
struct pollfd pollfds[MAX_POLLFDS];
|
||||
int i, maxfd, npollfds;
|
||||
ADNS_SOCKET fd;
|
||||
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
|
||||
if (tv_mod && (!*tv_mod || (*tv_mod)->tv_sec || (*tv_mod)->tv_usec)) {
|
||||
/* The caller is planning to sleep. */
|
||||
adns__must_gettimeofday(ads,&now,&tv_nowbuf);
|
||||
if (!now) { inter_immed(tv_mod,tv_tobuf); goto xit; }
|
||||
adns__timeouts(ads, 0, tv_mod,tv_tobuf, *now);
|
||||
}
|
||||
|
||||
npollfds= adns__pollfds(ads,pollfds);
|
||||
maxfd= *maxfd_io;
|
||||
for (i=0; i<npollfds; i++) {
|
||||
fd= pollfds[i].fd;
|
||||
if ((int)fd >= maxfd) maxfd= fd+1;
|
||||
if (pollfds[i].events & POLLIN) FD_SET(fd,readfds_io);
|
||||
if (pollfds[i].events & POLLOUT) FD_SET(fd,writefds_io);
|
||||
if (pollfds[i].events & POLLPRI) FD_SET(fd,exceptfds_io);
|
||||
}
|
||||
*maxfd_io= maxfd;
|
||||
|
||||
xit:
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
}
|
||||
|
||||
void adns_afterselect(adns_state ads, int maxfd, const fd_set *readfds,
|
||||
const fd_set *writefds, const fd_set *exceptfds,
|
||||
const struct timeval *now) {
|
||||
struct timeval tv_buf;
|
||||
struct pollfd pollfds[MAX_POLLFDS];
|
||||
int npollfds, i;
|
||||
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
adns__must_gettimeofday(ads,&now,&tv_buf);
|
||||
if (!now) goto xit;
|
||||
adns_processtimeouts(ads,now);
|
||||
|
||||
npollfds= adns__pollfds(ads,pollfds);
|
||||
for (i=0; i<npollfds; i++) pollfds[i].revents= POLLIN|POLLOUT|POLLPRI;
|
||||
adns__fdevents(ads,
|
||||
pollfds,npollfds,
|
||||
maxfd,readfds,writefds,exceptfds,
|
||||
*now, 0);
|
||||
xit:
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
}
|
||||
|
||||
/* General helpful functions. */
|
||||
|
||||
void adns_globalsystemfailure(adns_state ads) {
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
|
||||
while (ads->udpw.head) adns__query_fail(ads->udpw.head, adns_s_systemfail);
|
||||
while (ads->tcpw.head) adns__query_fail(ads->tcpw.head, adns_s_systemfail);
|
||||
|
||||
switch (ads->tcpstate) {
|
||||
case server_connecting:
|
||||
case server_ok:
|
||||
adns__tcp_broken(ads,0,0);
|
||||
break;
|
||||
case server_disconnected:
|
||||
case server_broken:
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
}
|
||||
|
||||
int adns_processany(adns_state ads) {
|
||||
int r, i;
|
||||
struct timeval now;
|
||||
struct pollfd pollfds[MAX_POLLFDS];
|
||||
int npollfds;
|
||||
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
|
||||
r= gettimeofday(&now,0);
|
||||
if (!r) adns_processtimeouts(ads,&now);
|
||||
|
||||
/* We just use adns__fdevents to loop over the fd's trying them.
|
||||
* This seems more sensible than calling select, since we're most
|
||||
* likely just to want to do a adns_socket_read on one or two fds anyway.
|
||||
*/
|
||||
npollfds= adns__pollfds(ads,pollfds);
|
||||
for (i=0; i<npollfds; i++) pollfds[i].revents= pollfds[i].events & ~POLLPRI;
|
||||
adns__fdevents(ads,
|
||||
pollfds,npollfds,
|
||||
0,0,0,0,
|
||||
now,&r);
|
||||
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void adns__autosys(adns_state ads, struct timeval now) {
|
||||
if (ads->iflags & adns_if_noautosys) return;
|
||||
adns_processany(ads);
|
||||
}
|
||||
|
||||
int adns__internal_check(adns_state ads,
|
||||
adns_query *query_io,
|
||||
adns_answer **answer,
|
||||
void **context_r) {
|
||||
adns_query qu;
|
||||
|
||||
qu= *query_io;
|
||||
if (!qu) {
|
||||
if (ads->output.head) {
|
||||
qu= ads->output.head;
|
||||
} else if (ads->udpw.head || ads->tcpw.head) {
|
||||
return EAGAIN;
|
||||
} else {
|
||||
return ESRCH;
|
||||
}
|
||||
} else {
|
||||
if (qu->id>=0) return EAGAIN;
|
||||
}
|
||||
LIST_UNLINK(ads->output,qu);
|
||||
*answer= qu->answer;
|
||||
if (context_r) *context_r= qu->ctx.ext;
|
||||
*query_io= qu;
|
||||
free(qu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int adns_wait(adns_state ads,
|
||||
adns_query *query_io,
|
||||
adns_answer **answer_r,
|
||||
void **context_r) {
|
||||
int r, maxfd, rsel;
|
||||
fd_set readfds, writefds, exceptfds;
|
||||
struct timeval tvbuf, *tvp;
|
||||
|
||||
adns__consistency(ads,*query_io,cc_entex);
|
||||
for (;;) {
|
||||
r= adns__internal_check(ads,query_io,answer_r,context_r);
|
||||
if (r != EAGAIN) break;
|
||||
maxfd= 0; tvp= 0;
|
||||
FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds);
|
||||
adns_beforeselect(ads,&maxfd,&readfds,&writefds,&exceptfds,&tvp,&tvbuf,0);
|
||||
assert(tvp);
|
||||
ADNS_CLEAR_ERRNO;
|
||||
rsel= select(maxfd,&readfds,&writefds,&exceptfds,tvp);
|
||||
ADNS_CAPTURE_ERRNO;
|
||||
if (rsel==-1) {
|
||||
if (errno == EINTR) {
|
||||
if (ads->iflags & adns_if_eintr) { r= EINTR; break; }
|
||||
} else {
|
||||
adns__diag(ads,-1,0,"select failed in wait: %s",strerror(errno));
|
||||
adns_globalsystemfailure(ads);
|
||||
}
|
||||
} else {
|
||||
assert(rsel >= 0);
|
||||
adns_afterselect(ads,maxfd,&readfds,&writefds,&exceptfds,0);
|
||||
}
|
||||
}
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
return r;
|
||||
}
|
||||
|
||||
int adns_check(adns_state ads,
|
||||
adns_query *query_io,
|
||||
adns_answer **answer_r,
|
||||
void **context_r) {
|
||||
struct timeval now;
|
||||
int r;
|
||||
|
||||
adns__consistency(ads,*query_io,cc_entex);
|
||||
r= gettimeofday(&now,0);
|
||||
if (!r) adns__autosys(ads,now);
|
||||
|
||||
r= adns__internal_check(ads,query_io,answer_r,context_r);
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
return r;
|
||||
}
|
||||
@@ -0,0 +1,369 @@
|
||||
/*
|
||||
* general.c
|
||||
* - diagnostic functions
|
||||
* - vbuf handling
|
||||
*/
|
||||
/*
|
||||
* This file is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
*
|
||||
* It is part of adns, which is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
* Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef ADNS_JGAA_WIN32
|
||||
# include "adns_win32.h"
|
||||
#else
|
||||
# include <unistd.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
/* Core diagnostic functions */
|
||||
|
||||
void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
|
||||
int serv, adns_query qu, const char *fmt, va_list al) {
|
||||
const char *bef, *aft;
|
||||
vbuf vb;
|
||||
|
||||
if (!ads->diagfile ||
|
||||
(!(ads->iflags & adns_if_debug) && (!prevent || (ads->iflags & prevent))))
|
||||
return;
|
||||
|
||||
if (ads->iflags & adns_if_logpid) {
|
||||
fprintf(ads->diagfile,"adns%s [%ld]: ",pfx,(long)getpid());
|
||||
} else {
|
||||
fprintf(ads->diagfile,"adns%s: ",pfx);
|
||||
}
|
||||
|
||||
vfprintf(ads->diagfile,fmt,al);
|
||||
|
||||
bef= " (";
|
||||
aft= "\n";
|
||||
|
||||
if (qu && qu->query_dgram) {
|
||||
adns__vbuf_init(&vb);
|
||||
fprintf(ads->diagfile,"%sQNAME=%s, QTYPE=%s",
|
||||
bef,
|
||||
adns__diag_domain(qu->ads,-1,0, &vb,
|
||||
qu->query_dgram,qu->query_dglen,DNS_HDRSIZE),
|
||||
qu->typei ? qu->typei->rrtname : "<unknown>");
|
||||
if (qu->typei && qu->typei->fmtname)
|
||||
fprintf(ads->diagfile,"(%s)",qu->typei->fmtname);
|
||||
bef=", "; aft=")\n";
|
||||
adns__vbuf_free(&vb);
|
||||
}
|
||||
|
||||
if (serv>=0) {
|
||||
fprintf(ads->diagfile,"%sNS=%s",bef,inet_ntoa(ads->servers[serv].addr));
|
||||
bef=", "; aft=")\n";
|
||||
}
|
||||
|
||||
fputs(aft,ads->diagfile);
|
||||
}
|
||||
|
||||
void adns__debug(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
|
||||
va_list al;
|
||||
|
||||
va_start(al,fmt);
|
||||
adns__vdiag(ads," debug",0,serv,qu,fmt,al);
|
||||
va_end(al);
|
||||
}
|
||||
|
||||
void adns__warn(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
|
||||
va_list al;
|
||||
|
||||
va_start(al,fmt);
|
||||
adns__vdiag(ads," warning",adns_if_noerrprint|adns_if_noserverwarn,serv,qu,fmt,al);
|
||||
va_end(al);
|
||||
}
|
||||
|
||||
void adns__diag(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
|
||||
va_list al;
|
||||
|
||||
va_start(al,fmt);
|
||||
adns__vdiag(ads,"",adns_if_noerrprint,serv,qu,fmt,al);
|
||||
va_end(al);
|
||||
}
|
||||
|
||||
/* vbuf functions */
|
||||
|
||||
void adns__vbuf_init(vbuf *vb) {
|
||||
vb->used= vb->avail= 0; vb->buf= 0;
|
||||
}
|
||||
|
||||
int adns__vbuf_ensure(vbuf *vb, int want) {
|
||||
void *nb;
|
||||
|
||||
if (vb->avail >= want) return 1;
|
||||
nb= realloc(vb->buf,want); if (!nb) return 0;
|
||||
vb->buf= nb;
|
||||
vb->avail= want;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void adns__vbuf_appendq(vbuf *vb, const byte *data, int len) {
|
||||
memcpy(vb->buf+vb->used,data,len);
|
||||
vb->used+= len;
|
||||
}
|
||||
|
||||
int adns__vbuf_append(vbuf *vb, const byte *data, int len) {
|
||||
int newlen;
|
||||
void *nb;
|
||||
|
||||
newlen= vb->used+len;
|
||||
if (vb->avail < newlen) {
|
||||
if (newlen<20) newlen= 20;
|
||||
newlen <<= 1;
|
||||
nb= realloc(vb->buf,newlen);
|
||||
if (!nb) { newlen= vb->used+len; nb= realloc(vb->buf,newlen); }
|
||||
if (!nb) return 0;
|
||||
vb->buf= nb;
|
||||
vb->avail= newlen;
|
||||
}
|
||||
adns__vbuf_appendq(vb,data,len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int adns__vbuf_appendstr(vbuf *vb, const char *data) {
|
||||
int l;
|
||||
l= strlen(data);
|
||||
return adns__vbuf_append(vb,data,l);
|
||||
}
|
||||
|
||||
void adns__vbuf_free(vbuf *vb) {
|
||||
free(vb->buf);
|
||||
adns__vbuf_init(vb);
|
||||
}
|
||||
|
||||
/* Additional diagnostic functions */
|
||||
|
||||
const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
|
||||
vbuf *vb, const byte *dgram, int dglen, int cbyte) {
|
||||
adns_status st;
|
||||
|
||||
st= adns__parse_domain(ads,serv,qu,vb, pdf_quoteok, dgram,dglen,&cbyte,dglen);
|
||||
if (st == adns_s_nomemory) {
|
||||
return "<cannot report domain... out of memory>";
|
||||
}
|
||||
if (st) {
|
||||
vb->used= 0;
|
||||
if (!(adns__vbuf_appendstr(vb,"<bad format... ") &&
|
||||
adns__vbuf_appendstr(vb,adns_strerror(st)) &&
|
||||
adns__vbuf_appendstr(vb,">") &&
|
||||
adns__vbuf_append(vb,"",1))) {
|
||||
return "<cannot report bad format... out of memory>";
|
||||
}
|
||||
}
|
||||
if (!vb->used) {
|
||||
adns__vbuf_appendstr(vb,"<truncated ...>");
|
||||
adns__vbuf_append(vb,"",1);
|
||||
}
|
||||
return vb->buf;
|
||||
}
|
||||
|
||||
adns_status adns_rr_info(adns_rrtype type,
|
||||
const char **rrtname_r, const char **fmtname_r,
|
||||
int *len_r,
|
||||
const void *datap, char **data_r) {
|
||||
const typeinfo *typei;
|
||||
vbuf vb;
|
||||
adns_status st;
|
||||
|
||||
typei= adns__findtype(type);
|
||||
if (!typei) return adns_s_unknownrrtype;
|
||||
|
||||
if (rrtname_r) *rrtname_r= typei->rrtname;
|
||||
if (fmtname_r) *fmtname_r= typei->fmtname;
|
||||
if (len_r) *len_r= typei->rrsz;
|
||||
|
||||
if (!datap) return adns_s_ok;
|
||||
|
||||
adns__vbuf_init(&vb);
|
||||
st= typei->convstring(&vb,datap);
|
||||
if (st) goto x_freevb;
|
||||
if (!adns__vbuf_append(&vb,"",1)) { st= adns_s_nomemory; goto x_freevb; }
|
||||
assert((int)strlen(vb.buf) == vb.used-1);
|
||||
*data_r= realloc(vb.buf,vb.used);
|
||||
if (!*data_r) *data_r= vb.buf;
|
||||
return adns_s_ok;
|
||||
|
||||
x_freevb:
|
||||
adns__vbuf_free(&vb);
|
||||
return st;
|
||||
}
|
||||
|
||||
|
||||
#define SINFO(n,s) { adns_s_##n, #n, s }
|
||||
|
||||
static const struct sinfo {
|
||||
adns_status st;
|
||||
const char *abbrev;
|
||||
const char *string;
|
||||
} sinfos[]= {
|
||||
SINFO( ok, "OK" ),
|
||||
|
||||
SINFO( nomemory, "Out of memory" ),
|
||||
SINFO( unknownrrtype, "Query not implemented in DNS library" ),
|
||||
SINFO( systemfail, "General resolver or system failure" ),
|
||||
|
||||
SINFO( timeout, "DNS query timed out" ),
|
||||
SINFO( allservfail, "All nameservers failed" ),
|
||||
SINFO( norecurse, "Recursion denied by nameserver" ),
|
||||
SINFO( invalidresponse, "Nameserver sent bad response" ),
|
||||
SINFO( unknownformat, "Nameserver used unknown format" ),
|
||||
|
||||
SINFO( rcodeservfail, "Nameserver reports failure" ),
|
||||
SINFO( rcodeformaterror, "Query not understood by nameserver" ),
|
||||
SINFO( rcodenotimplemented, "Query not implemented by nameserver" ),
|
||||
SINFO( rcoderefused, "Query refused by nameserver" ),
|
||||
SINFO( rcodeunknown, "Nameserver sent unknown response code" ),
|
||||
|
||||
SINFO( inconsistent, "Inconsistent resource records in DNS" ),
|
||||
SINFO( prohibitedcname, "DNS alias found where canonical name wanted" ),
|
||||
SINFO( answerdomaininvalid, "Found syntactically invalid domain name" ),
|
||||
SINFO( answerdomaintoolong, "Found overly-long domain name" ),
|
||||
SINFO( invaliddata, "Found invalid DNS data" ),
|
||||
|
||||
SINFO( querydomainwrong, "Domain invalid for particular DNS query type" ),
|
||||
SINFO( querydomaininvalid, "Domain name is syntactically invalid" ),
|
||||
SINFO( querydomaintoolong, "Domain name or component is too long" ),
|
||||
|
||||
SINFO( nxdomain, "No such domain" ),
|
||||
SINFO( nodata, "No such data" )
|
||||
};
|
||||
|
||||
static int si_compar(const void *key, const void *elem) {
|
||||
const adns_status *st= key;
|
||||
const struct sinfo *si= elem;
|
||||
|
||||
return *st < si->st ? -1 : *st > si->st ? 1 : 0;
|
||||
}
|
||||
|
||||
static const struct sinfo *findsinfo(adns_status st) {
|
||||
return bsearch(&st,sinfos,sizeof(sinfos)/sizeof(*sinfos),sizeof(*sinfos),si_compar);
|
||||
}
|
||||
|
||||
const char *adns_strerror(adns_status st) {
|
||||
const struct sinfo *si;
|
||||
|
||||
si= findsinfo(st);
|
||||
return si->string;
|
||||
}
|
||||
|
||||
const char *adns_errabbrev(adns_status st) {
|
||||
const struct sinfo *si;
|
||||
|
||||
si= findsinfo(st);
|
||||
return si->abbrev;
|
||||
}
|
||||
|
||||
|
||||
#define STINFO(max) { adns_s_max_##max, #max }
|
||||
|
||||
static const struct stinfo {
|
||||
adns_status stmax;
|
||||
const char *abbrev;
|
||||
} stinfos[]= {
|
||||
{ adns_s_ok, "ok" },
|
||||
STINFO( localfail ),
|
||||
STINFO( remotefail ),
|
||||
STINFO( tempfail ),
|
||||
STINFO( misconfig ),
|
||||
STINFO( misquery ),
|
||||
STINFO( permfail )
|
||||
};
|
||||
|
||||
static int sti_compar(const void *key, const void *elem) {
|
||||
const adns_status *st= key;
|
||||
const struct stinfo *sti= elem;
|
||||
|
||||
adns_status here, min, max;
|
||||
|
||||
here= *st;
|
||||
min= (sti==stinfos) ? 0 : sti[-1].stmax+1;
|
||||
max= sti->stmax;
|
||||
|
||||
return here < min ? -1 : here > max ? 1 : 0;
|
||||
}
|
||||
|
||||
const char *adns_errtypeabbrev(adns_status st) {
|
||||
const struct stinfo *sti;
|
||||
|
||||
sti= bsearch(&st,stinfos,sizeof(stinfos)/sizeof(*stinfos),sizeof(*stinfos),sti_compar);
|
||||
return sti->abbrev;
|
||||
}
|
||||
|
||||
|
||||
void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
|
||||
int (*needswap)(void *context, const void *a, const void *b),
|
||||
void *context) {
|
||||
byte *data= array;
|
||||
int i, place;
|
||||
|
||||
for (i=0; i<nobjs; i++) {
|
||||
for (place= i;
|
||||
place>0 && needswap(context, data + (place-1)*sz, data + i*sz);
|
||||
place--);
|
||||
if (place != i) {
|
||||
memcpy(tempbuf, data + i*sz, sz);
|
||||
memmove(data + (place+1)*sz, data + place*sz, (i-place)*sz);
|
||||
memcpy(data + place*sz, tempbuf, sz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* SIGPIPE protection. */
|
||||
/* Not required under Win32 with MSVC */
|
||||
|
||||
void adns__sigpipe_protect(adns_state ads) {
|
||||
#ifndef ADNS_JGAA_WIN32
|
||||
sigset_t toblock;
|
||||
struct sigaction sa;
|
||||
int r;
|
||||
|
||||
if (ads->iflags & adns_if_nosigpipe) return;
|
||||
|
||||
sigfillset(&toblock);
|
||||
sigdelset(&toblock,SIGPIPE);
|
||||
|
||||
sa.sa_handler= SIG_IGN;
|
||||
sigfillset(&sa.sa_mask);
|
||||
sa.sa_flags= 0;
|
||||
|
||||
r= sigprocmask(SIG_SETMASK,&toblock,&ads->stdsigmask); assert(!r);
|
||||
r= sigaction(SIGPIPE,&sa,&ads->stdsigpipe); assert(!r);
|
||||
#endif
|
||||
}
|
||||
|
||||
void adns__sigpipe_unprotect(adns_state ads) {
|
||||
#ifndef ADNS_JGAA_WIN32
|
||||
int r;
|
||||
|
||||
if (ads->iflags & adns_if_nosigpipe) return;
|
||||
|
||||
r= sigaction(SIGPIPE,&ads->stdsigpipe,0); assert(!r);
|
||||
r= sigprocmask(SIG_SETMASK,&ads->stdsigmask,0); assert(!r);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,721 @@
|
||||
/*
|
||||
* internal.h
|
||||
* - declarations of private objects with external linkage (adns__*)
|
||||
* - definitons of internal macros
|
||||
* - comments regarding library data structures
|
||||
*/
|
||||
/*
|
||||
* This file is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
*
|
||||
* It is part of adns, which is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
* Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef ADNS_INTERNAL_H_INCLUDED
|
||||
#define ADNS_INTERNAL_H_INCLUDED
|
||||
|
||||
#include "config.h"
|
||||
typedef unsigned char byte;
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef ADNS_JGAA_WIN32
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef ADNS_JGAA_WIN32
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "adns.h"
|
||||
#include "dlist.h"
|
||||
|
||||
#ifdef ADNS_REGRESS_TEST
|
||||
# include "hredirect.h"
|
||||
#endif
|
||||
|
||||
/* Configuration and constants */
|
||||
|
||||
#define MAXSERVERS 5
|
||||
#define MAXSORTLIST 15
|
||||
#define UDPMAXRETRIES 15
|
||||
#define UDPRETRYMS 2000
|
||||
#define TCPWAITMS 30000
|
||||
#define TCPCONNMS 14000
|
||||
#define TCPIDLEMS 30000
|
||||
#define MAXTTLBELIEVE (7*86400) /* any TTL > 7 days is capped */
|
||||
|
||||
#define DNS_PORT 53
|
||||
#define DNS_MAXUDP 512
|
||||
#define DNS_MAXLABEL 63
|
||||
#define DNS_MAXDOMAIN 255
|
||||
#define DNS_HDRSIZE 12
|
||||
#define DNS_IDOFFSET 0
|
||||
#define DNS_CLASS_IN 1
|
||||
|
||||
#define DNS_INADDR_ARPA "in-addr", "arpa"
|
||||
|
||||
#define MAX_POLLFDS ADNS_POLLFDS_RECOMMENDED
|
||||
|
||||
typedef enum {
|
||||
cc_user,
|
||||
cc_entex,
|
||||
cc_freq
|
||||
} consistency_checks;
|
||||
|
||||
typedef enum {
|
||||
rcode_noerror,
|
||||
rcode_formaterror,
|
||||
rcode_servfail,
|
||||
rcode_nxdomain,
|
||||
rcode_notimp,
|
||||
rcode_refused
|
||||
} dns_rcode;
|
||||
|
||||
/* Shared data structures */
|
||||
|
||||
typedef union {
|
||||
adns_status status;
|
||||
char *cp;
|
||||
adns_rrtype type;
|
||||
int i;
|
||||
struct in_addr ia;
|
||||
unsigned long ul;
|
||||
} rr_align;
|
||||
|
||||
typedef struct {
|
||||
int used, avail;
|
||||
byte *buf;
|
||||
} vbuf;
|
||||
|
||||
typedef struct {
|
||||
adns_state ads;
|
||||
adns_query qu;
|
||||
int serv;
|
||||
const byte *dgram;
|
||||
int dglen, nsstart, nscount, arcount;
|
||||
struct timeval now;
|
||||
} parseinfo;
|
||||
|
||||
typedef struct {
|
||||
adns_rrtype type;
|
||||
const char *rrtname;
|
||||
const char *fmtname;
|
||||
int rrsz;
|
||||
|
||||
void (*makefinal)(adns_query qu, void *data);
|
||||
/* Change memory management of *data.
|
||||
* Previously, used alloc_interim, now use alloc_final.
|
||||
*/
|
||||
|
||||
adns_status (*convstring)(vbuf *vb, const void *data);
|
||||
/* Converts the RR data to a string representation in vbuf.
|
||||
* vbuf will be appended to (it must have been initialised),
|
||||
* and will not be null-terminated by convstring.
|
||||
*/
|
||||
|
||||
adns_status (*parse)(const parseinfo *pai, int cbyte, int max, void *store_r);
|
||||
/* Parse one RR, in dgram of length dglen, starting at cbyte and
|
||||
* extending until at most max.
|
||||
*
|
||||
* The RR should be stored at *store_r, of length qu->typei->rrsz.
|
||||
*
|
||||
* If there is an overrun which might indicate truncation, it should set
|
||||
* *rdstart to -1; otherwise it may set it to anything else positive.
|
||||
*
|
||||
* nsstart is the offset of the authority section.
|
||||
*/
|
||||
|
||||
int (*diff_needswap)(adns_state ads, const void *datap_a, const void *datap_b);
|
||||
/* Returns !0 if RR a should be strictly after RR b in the sort order,
|
||||
* 0 otherwise. Must not fail.
|
||||
*/
|
||||
} typeinfo;
|
||||
|
||||
typedef struct allocnode {
|
||||
struct allocnode *next, *back;
|
||||
} allocnode;
|
||||
|
||||
union maxalign {
|
||||
byte d[1];
|
||||
struct in_addr ia;
|
||||
long l;
|
||||
void *p;
|
||||
void (*fp)(void);
|
||||
union maxalign *up;
|
||||
} data;
|
||||
|
||||
typedef struct {
|
||||
void *ext;
|
||||
void (*callback)(adns_query parent, adns_query child);
|
||||
union {
|
||||
adns_rr_addr ptr_parent_addr;
|
||||
adns_rr_hostaddr *hostaddr;
|
||||
} info;
|
||||
} qcontext;
|
||||
|
||||
struct adns__query {
|
||||
adns_state ads;
|
||||
enum { query_tosend, query_tcpw, query_childw, query_done } state;
|
||||
adns_query back, next, parent;
|
||||
struct { adns_query head, tail; } children;
|
||||
struct { adns_query back, next; } siblings;
|
||||
struct { allocnode *head, *tail; } allocations;
|
||||
int interim_allocd, preserved_allocd;
|
||||
void *final_allocspace;
|
||||
|
||||
const typeinfo *typei;
|
||||
byte *query_dgram;
|
||||
int query_dglen;
|
||||
|
||||
vbuf vb;
|
||||
/* General-purpose messing-about buffer.
|
||||
* Wherever a `big' interface is crossed, this may be corrupted/changed
|
||||
* unless otherwise specified.
|
||||
*/
|
||||
|
||||
adns_answer *answer;
|
||||
/* This is allocated when a query is submitted, to avoid being unable
|
||||
* to relate errors to queries if we run out of memory. During
|
||||
* query processing status, rrs is 0. cname is set if
|
||||
* we found a cname (this corresponds to cname_dgram in the query
|
||||
* structure). type is set from the word go. nrrs and rrs
|
||||
* are set together, when we find how many rrs there are.
|
||||
* owner is set during querying unless we're doing searchlist,
|
||||
* in which case it is set only when we find an answer.
|
||||
*/
|
||||
|
||||
byte *cname_dgram;
|
||||
int cname_dglen, cname_begin;
|
||||
/* If non-0, has been allocated using . */
|
||||
|
||||
vbuf search_vb;
|
||||
int search_origlen, search_pos, search_doneabs;
|
||||
/* Used by the searching algorithm. The query domain in textual form
|
||||
* is copied into the vbuf, and _origlen set to its length. Then
|
||||
* we walk the searchlist, if we want to. _pos says where we are
|
||||
* (next entry to try), and _doneabs says whether we've done the
|
||||
* absolute query yet (0=not yet, 1=done, -1=must do straight away,
|
||||
* but not done yet). If flags doesn't have adns_qf_search then
|
||||
* the vbuf is initialised but empty and everything else is zero.
|
||||
*/
|
||||
|
||||
int id, flags, retries;
|
||||
int udpnextserver;
|
||||
unsigned long udpsent; /* bitmap indexed by server */
|
||||
struct timeval timeout;
|
||||
time_t expires; /* Earliest expiry time of any record we used. */
|
||||
|
||||
qcontext ctx;
|
||||
|
||||
/* Possible states:
|
||||
*
|
||||
* state Queue child id nextudpserver udpsent tcpfailed
|
||||
*
|
||||
* tosend NONE null >=0 0 zero zero
|
||||
* tosend udpw null >=0 any nonzero zero
|
||||
* tosend NONE null >=0 any nonzero zero
|
||||
*
|
||||
* tcpw tcpw null >=0 irrelevant any any
|
||||
*
|
||||
* child childw set >=0 irrelevant irrelevant irrelevant
|
||||
* child NONE null >=0 irrelevant irrelevant irrelevant
|
||||
* done output null -1 irrelevant irrelevant irrelevant
|
||||
*
|
||||
* Queries are only not on a queue when they are actually being processed.
|
||||
* Queries in state tcpw/tcpw have been sent (or are in the to-send buffer)
|
||||
* iff the tcp connection is in state server_ok.
|
||||
*
|
||||
* +------------------------+
|
||||
* START -----> | tosend/NONE |
|
||||
* +------------------------+
|
||||
* / |\ \
|
||||
* too big for UDP / UDP timeout \ \ send via UDP
|
||||
* send via TCP / more retries \ \
|
||||
* when conn'd / desired \ \
|
||||
* | | |
|
||||
* v | v
|
||||
* +-----------+ +-------------+
|
||||
* | tcpw/tcpw | ________ | tosend/udpw |
|
||||
* +-----------+ \ +-------------+
|
||||
* | | | UDP timeout | |
|
||||
* | | | no more | |
|
||||
* | | | retries | |
|
||||
* \ | TCP died | desired | |
|
||||
* \ \ no more | | |
|
||||
* \ \ servers | TCP / |
|
||||
* \ \ to try | timeout / |
|
||||
* got \ \ v |_ | got
|
||||
* reply \ _| +------------------+ / reply
|
||||
* \ | done/output FAIL | /
|
||||
* \ +------------------+ /
|
||||
* \ /
|
||||
* _| |_
|
||||
* (..... got reply ....)
|
||||
* / \
|
||||
* need child query/ies / \ no child query
|
||||
* / \
|
||||
* |_ _|
|
||||
* +---------------+ +----------------+
|
||||
* | childw/childw | ----------------> | done/output OK |
|
||||
* +---------------+ children done +----------------+
|
||||
*/
|
||||
};
|
||||
|
||||
struct query_queue { adns_query head, tail; };
|
||||
|
||||
struct adns__state {
|
||||
adns_initflags iflags;
|
||||
FILE *diagfile;
|
||||
int configerrno;
|
||||
struct query_queue udpw, tcpw, childw, output;
|
||||
adns_query forallnext;
|
||||
int nextid;
|
||||
ADNS_SOCKET udpsocket, tcpsocket;
|
||||
vbuf tcpsend, tcprecv;
|
||||
int nservers, nsortlist, nsearchlist, searchndots, tcpserver, tcprecv_skip;
|
||||
enum adns__tcpstate {
|
||||
server_disconnected, server_connecting,
|
||||
server_ok, server_broken
|
||||
} tcpstate;
|
||||
struct timeval tcptimeout;
|
||||
/* This will have tv_sec==0 if it is not valid. It will always be
|
||||
* valid if tcpstate _connecting. When _ok, it will be nonzero if
|
||||
* we are idle (ie, tcpw queue is empty), in which case it is the
|
||||
* absolute time when we will close the connection.
|
||||
*/
|
||||
#ifndef ADNS_JGAA_WIN32
|
||||
struct sigaction stdsigpipe;
|
||||
sigset_t stdsigmask;
|
||||
#endif
|
||||
struct pollfd pollfds_buf[MAX_POLLFDS];
|
||||
struct server {
|
||||
struct in_addr addr;
|
||||
} servers[MAXSERVERS];
|
||||
struct sortlist {
|
||||
struct in_addr base, mask;
|
||||
} sortlist[MAXSORTLIST];
|
||||
char **searchlist;
|
||||
};
|
||||
|
||||
/* From setup.c: */
|
||||
|
||||
int adns__setnonblock(adns_state ads, ADNS_SOCKET fd); /* => errno value */
|
||||
|
||||
/* From general.c: */
|
||||
|
||||
void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
|
||||
int serv, adns_query qu, const char *fmt, va_list al);
|
||||
|
||||
void adns__debug(adns_state ads, int serv, adns_query qu,
|
||||
const char *fmt, ...) PRINTFFORMAT(4,5);
|
||||
void adns__warn(adns_state ads, int serv, adns_query qu,
|
||||
const char *fmt, ...) PRINTFFORMAT(4,5);
|
||||
void adns__diag(adns_state ads, int serv, adns_query qu,
|
||||
const char *fmt, ...) PRINTFFORMAT(4,5);
|
||||
|
||||
int adns__vbuf_ensure(vbuf *vb, int want);
|
||||
int adns__vbuf_appendstr(vbuf *vb, const char *data); /* does not include nul */
|
||||
int adns__vbuf_append(vbuf *vb, const byte *data, int len);
|
||||
/* 1=>success, 0=>realloc failed */
|
||||
void adns__vbuf_appendq(vbuf *vb, const byte *data, int len);
|
||||
void adns__vbuf_init(vbuf *vb);
|
||||
void adns__vbuf_free(vbuf *vb);
|
||||
|
||||
const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
|
||||
vbuf *vb, const byte *dgram, int dglen, int cbyte);
|
||||
/* Unpicks a domain in a datagram and returns a string suitable for
|
||||
* printing it as. Never fails - if an error occurs, it will
|
||||
* return some kind of string describing the error.
|
||||
*
|
||||
* serv may be -1 and qu may be 0. vb must have been initialised,
|
||||
* and will be left in an arbitrary consistent state.
|
||||
*
|
||||
* Returns either vb->buf, or a pointer to a string literal. Do not modify
|
||||
* vb before using the return value.
|
||||
*/
|
||||
|
||||
void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
|
||||
int (*needswap)(void *context, const void *a, const void *b),
|
||||
void *context);
|
||||
/* Does an insertion sort of array which must contain nobjs objects
|
||||
* each sz bytes long. tempbuf must point to a buffer at least
|
||||
* sz bytes long. needswap should return !0 if a>b (strictly, ie
|
||||
* wrong order) 0 if a<=b (ie, order is fine).
|
||||
*/
|
||||
|
||||
void adns__sigpipe_protect(adns_state);
|
||||
void adns__sigpipe_unprotect(adns_state);
|
||||
/* If SIGPIPE protection is not disabled, will block all signals except
|
||||
* SIGPIPE, and set SIGPIPE's disposition to SIG_IGN. (And then restore.)
|
||||
* Each call to _protect must be followed by a call to _unprotect before
|
||||
* any significant amount of code gets to run, since the old signal mask
|
||||
* is stored in the adns structure.
|
||||
*/
|
||||
|
||||
/* From transmit.c: */
|
||||
|
||||
adns_status adns__mkquery(adns_state ads, vbuf *vb, int *id_r,
|
||||
const char *owner, int ol,
|
||||
const typeinfo *typei, adns_queryflags flags);
|
||||
/* Assembles a query packet in vb. A new id is allocated and returned.
|
||||
*/
|
||||
|
||||
adns_status adns__mkquery_frdgram(adns_state ads, vbuf *vb, int *id_r,
|
||||
const byte *qd_dgram, int qd_dglen, int qd_begin,
|
||||
adns_rrtype type, adns_queryflags flags);
|
||||
/* Same as adns__mkquery, but takes the owner domain from an existing datagram.
|
||||
* That domain must be correct and untruncated.
|
||||
*/
|
||||
|
||||
void adns__querysend_tcp(adns_query qu, struct timeval now);
|
||||
/* Query must be in state tcpw/tcpw; it will be sent if possible and
|
||||
* no further processing can be done on it for now. The connection
|
||||
* might be broken, but no reconnect will be attempted.
|
||||
*/
|
||||
|
||||
void adns__query_send(adns_query qu, struct timeval now);
|
||||
/* Query must be in state tosend/NONE; it will be moved to a new state,
|
||||
* and no further processing can be done on it for now.
|
||||
* (Resulting state is one of udp/timew, tcpwait/timew (if server not connected),
|
||||
* tcpsent/timew, child/childw or done/output.)
|
||||
* __query_send may decide to use either UDP or TCP depending whether
|
||||
* _qf_usevc is set (or has become set) and whether the query is too
|
||||
* large.
|
||||
*/
|
||||
|
||||
/* From query.c: */
|
||||
|
||||
adns_status adns__internal_submit(adns_state ads, adns_query *query_r,
|
||||
const typeinfo *typei, vbuf *qumsg_vb, int id,
|
||||
adns_queryflags flags, struct timeval now,
|
||||
const qcontext *ctx);
|
||||
/* Submits a query (for internal use, called during external submits).
|
||||
*
|
||||
* The new query is returned in *query_r, or we return adns_s_nomemory.
|
||||
*
|
||||
* The query datagram should already have been assembled in qumsg_vb;
|
||||
* the memory for it is _taken over_ by this routine whether it
|
||||
* succeeds or fails (if it succeeds, the vbuf is reused for qu->vb).
|
||||
*
|
||||
* *ctx is copied byte-for-byte into the query.
|
||||
*
|
||||
* When the child query is done, ctx->callback will be called. The
|
||||
* child will already have been taken off both the global list of
|
||||
* queries in ads and the list of children in the parent. The child
|
||||
* will be freed when the callback returns. The parent will have been
|
||||
* taken off the global childw queue.
|
||||
*
|
||||
* The callback should either call adns__query_done, if it is
|
||||
* complete, or adns__query_fail, if an error has occurred, in which
|
||||
* case the other children (if any) will be cancelled. If the parent
|
||||
* has more unfinished children (or has just submitted more) then the
|
||||
* callback may choose to wait for them - it must then put the parent
|
||||
* back on the childw queue.
|
||||
*/
|
||||
|
||||
void adns__search_next(adns_state ads, adns_query qu, struct timeval now);
|
||||
/* Walks down the searchlist for a query with adns_qf_search.
|
||||
* The query should have just had a negative response, or not had
|
||||
* any queries sent yet, and should not be on any queue.
|
||||
* The query_dgram if any will be freed and forgotten and a new
|
||||
* one constructed from the search_* members of the query.
|
||||
*
|
||||
* Cannot fail (in case of error, calls adns__query_fail).
|
||||
*/
|
||||
|
||||
void *adns__alloc_interim(adns_query qu, size_t sz);
|
||||
void *adns__alloc_preserved(adns_query qu, size_t sz);
|
||||
/* Allocates some memory, and records which query it came from
|
||||
* and how much there was.
|
||||
*
|
||||
* If an error occurs in the query, all the memory from _interim is
|
||||
* simply freed. If the query succeeds, one large buffer will be made
|
||||
* which is big enough for all these allocations, and then
|
||||
* adns__alloc_final will get memory from this buffer.
|
||||
*
|
||||
* _alloc_interim can fail (and return 0).
|
||||
* The caller must ensure that the query is failed.
|
||||
*
|
||||
* The memory from _preserved is is kept and transferred into the
|
||||
* larger buffer - unless we run out of memory, in which case it too
|
||||
* is freed. When you use _preserved you have to add code to the
|
||||
* x_nomem error exit case in adns__makefinal_query to clear out the
|
||||
* pointers you made to those allocations, because that's when they're
|
||||
* thrown away; you should also make a note in the declaration of
|
||||
* those pointer variables, to note that they are _preserved rather
|
||||
* than _interim. If they're in the answer, note it here:
|
||||
* answer->cname and answer->owner are _preserved.
|
||||
*/
|
||||
|
||||
void adns__transfer_interim(adns_query from, adns_query to, void *block, size_t sz);
|
||||
/* Transfers an interim allocation from one query to another, so that
|
||||
* the `to' query will have room for the data when we get to makefinal
|
||||
* and so that the free will happen when the `to' query is freed
|
||||
* rather than the `from' query.
|
||||
*
|
||||
* It is legal to call adns__transfer_interim with a null pointer; this
|
||||
* has no effect.
|
||||
*
|
||||
* _transfer_interim also ensures that the expiry time of the `to' query
|
||||
* is no later than that of the `from' query, so that child queries'
|
||||
* TTLs get inherited by their parents.
|
||||
*/
|
||||
|
||||
void *adns__alloc_mine(adns_query qu, size_t sz);
|
||||
/* Like _interim, but does not record the length for later
|
||||
* copying into the answer. This just ensures that the memory
|
||||
* will be freed when we're done with the query.
|
||||
*/
|
||||
|
||||
void *adns__alloc_final(adns_query qu, size_t sz);
|
||||
/* Cannot fail, and cannot return 0.
|
||||
*/
|
||||
|
||||
void adns__makefinal_block(adns_query qu, void **blpp, size_t sz);
|
||||
void adns__makefinal_str(adns_query qu, char **strp);
|
||||
|
||||
void adns__reset_preserved(adns_query qu);
|
||||
/* Resets all of the memory management stuff etc. to take account of
|
||||
* only the _preserved stuff from _alloc_preserved. Used when we find
|
||||
* an error somewhere and want to just report the error (with perhaps
|
||||
* CNAME, owner, etc. info), and also when we're halfway through RRs
|
||||
* in a datagram and discover that we need to retry the query.
|
||||
*/
|
||||
|
||||
void adns__query_done(adns_query qu);
|
||||
void adns__query_fail(adns_query qu, adns_status stat);
|
||||
|
||||
/* From reply.c: */
|
||||
|
||||
void adns__procdgram(adns_state ads, const byte *dgram, int len,
|
||||
int serv, int viatcp, struct timeval now);
|
||||
/* This function is allowed to cause new datagrams to be constructed
|
||||
* and sent, or even new queries to be started. However,
|
||||
* query-sending functions are not allowed to call any general event
|
||||
* loop functions in case they accidentally call this.
|
||||
*
|
||||
* Ie, receiving functions may call sending functions.
|
||||
* Sending functions may NOT call receiving functions.
|
||||
*/
|
||||
|
||||
/* From types.c: */
|
||||
|
||||
const typeinfo *adns__findtype(adns_rrtype type);
|
||||
|
||||
/* From parse.c: */
|
||||
|
||||
typedef struct {
|
||||
adns_state ads;
|
||||
adns_query qu;
|
||||
int serv;
|
||||
const byte *dgram;
|
||||
int dglen, max, cbyte, namelen;
|
||||
int *dmend_r;
|
||||
} findlabel_state;
|
||||
|
||||
void adns__findlabel_start(findlabel_state *fls, adns_state ads,
|
||||
int serv, adns_query qu,
|
||||
const byte *dgram, int dglen, int max,
|
||||
int dmbegin, int *dmend_rlater);
|
||||
/* Finds labels in a domain in a datagram.
|
||||
*
|
||||
* Call this routine first.
|
||||
* dmend_rlater may be null. ads (and of course fls) may not be.
|
||||
* serv may be -1, qu may be null - they are for error reporting.
|
||||
*/
|
||||
|
||||
adns_status adns__findlabel_next(findlabel_state *fls, int *lablen_r, int *labstart_r);
|
||||
/* Then, call this one repeatedly.
|
||||
*
|
||||
* It will return adns_s_ok if all is well, and tell you the length
|
||||
* and start of successive labels. labstart_r may be null, but
|
||||
* lablen_r must not be.
|
||||
*
|
||||
* After the last label, it will return with *lablen_r zero.
|
||||
* Do not then call it again; instead, just throw away the findlabel_state.
|
||||
*
|
||||
* *dmend_rlater will have been set to point to the next part of
|
||||
* the datagram after the label (or after the uncompressed part,
|
||||
* if compression was used). *namelen_rlater will have been set
|
||||
* to the length of the domain name (total length of labels plus
|
||||
* 1 for each intervening dot).
|
||||
*
|
||||
* If the datagram appears to be truncated, *lablen_r will be -1.
|
||||
* *dmend_rlater, *labstart_r and *namelen_r may contain garbage.
|
||||
* Do not call _next again.
|
||||
*
|
||||
* There may also be errors, in which case *dmend_rlater,
|
||||
* *namelen_rlater, *lablen_r and *labstart_r may contain garbage.
|
||||
* Do not then call findlabel_next again.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
pdf_quoteok= 0x001
|
||||
} parsedomain_flags;
|
||||
|
||||
adns_status adns__parse_domain(adns_state ads, int serv, adns_query qu,
|
||||
vbuf *vb, parsedomain_flags flags,
|
||||
const byte *dgram, int dglen, int *cbyte_io, int max);
|
||||
/* vb must already have been initialised; it will be reset if necessary.
|
||||
* If there is truncation, vb->used will be set to 0; otherwise
|
||||
* (if there is no error) vb will be null-terminated.
|
||||
* If there is an error vb and *cbyte_io may be left indeterminate.
|
||||
*
|
||||
* serv may be -1 and qu may be 0 - they are used for error reporting only.
|
||||
*/
|
||||
|
||||
adns_status adns__parse_domain_more(findlabel_state *fls, adns_state ads,
|
||||
adns_query qu, vbuf *vb, parsedomain_flags flags,
|
||||
const byte *dgram);
|
||||
/* Like adns__parse_domain, but you pass it a pre-initialised findlabel_state,
|
||||
* for continuing an existing domain or some such of some kind. Also, unlike
|
||||
* _parse_domain, the domain data will be appended to vb, rather than replacing
|
||||
* the existing contents.
|
||||
*/
|
||||
|
||||
adns_status adns__findrr(adns_query qu, int serv,
|
||||
const byte *dgram, int dglen, int *cbyte_io,
|
||||
int *type_r, int *class_r, unsigned long *ttl_r,
|
||||
int *rdlen_r, int *rdstart_r,
|
||||
int *ownermatchedquery_r);
|
||||
/* Finds the extent and some of the contents of an RR in a datagram
|
||||
* and does some checks. The datagram is *dgram, length dglen, and
|
||||
* the RR starts at *cbyte_io (which is updated afterwards to point
|
||||
* to the end of the RR).
|
||||
*
|
||||
* The type, class, TTL and RRdata length and start are returned iff
|
||||
* the corresponding pointer variables are not null. type_r, class_r
|
||||
* and ttl_r may not be null. The TTL will be capped.
|
||||
*
|
||||
* If ownermatchedquery_r != 0 then the owner domain of this
|
||||
* RR will be compared with that in the query (or, if the query
|
||||
* has gone to a CNAME lookup, with the canonical name).
|
||||
* In this case, *ownermatchedquery_r will be set to 0 or 1.
|
||||
* The query datagram (or CNAME datagram) MUST be valid and not truncated.
|
||||
*
|
||||
* If there is truncation then *type_r will be set to -1 and
|
||||
* *cbyte_io, *class_r, *rdlen_r, *rdstart_r and *eo_matched_r will be
|
||||
* undefined.
|
||||
*
|
||||
* qu must obviously be non-null.
|
||||
*
|
||||
* If an error is returned then *type_r will be undefined too.
|
||||
*/
|
||||
|
||||
adns_status adns__findrr_anychk(adns_query qu, int serv,
|
||||
const byte *dgram, int dglen, int *cbyte_io,
|
||||
int *type_r, int *class_r, unsigned long *ttl_r,
|
||||
int *rdlen_r, int *rdstart_r,
|
||||
const byte *eo_dgram, int eo_dglen, int eo_cbyte,
|
||||
int *eo_matched_r);
|
||||
/* Like adns__findrr_checked, except that the datagram and
|
||||
* owner to compare with can be specified explicitly.
|
||||
*
|
||||
* If the caller thinks they know what the owner of the RR ought to
|
||||
* be they can pass in details in eo_*: this is another (or perhaps
|
||||
* the same datagram), and a pointer to where the putative owner
|
||||
* starts in that datagram. In this case *eo_matched_r will be set
|
||||
* to 1 if the datagram matched or 0 if it did not. Either
|
||||
* both eo_dgram and eo_matched_r must both be non-null, or they
|
||||
* must both be null (in which case eo_dglen and eo_cbyte will be ignored).
|
||||
* The eo datagram and contained owner domain MUST be valid and
|
||||
* untruncated.
|
||||
*/
|
||||
|
||||
void adns__update_expires(adns_query qu, unsigned long ttl, struct timeval now);
|
||||
/* Updates the `expires' field in the query, so that it doesn't exceed
|
||||
* now + ttl.
|
||||
*/
|
||||
|
||||
int vbuf__append_quoted1035(vbuf *vb, const byte *buf, int len);
|
||||
|
||||
/* From event.c: */
|
||||
|
||||
void adns__tcp_broken(adns_state ads, const char *what, const char *why);
|
||||
/* what and why may be both 0, or both non-0. */
|
||||
|
||||
void adns__tcp_tryconnect(adns_state ads, struct timeval now);
|
||||
|
||||
void adns__autosys(adns_state ads, struct timeval now);
|
||||
/* Make all the system calls we want to if the application wants us to.
|
||||
* Must not be called from within adns internal processing functions,
|
||||
* lest we end up in recursive descent !
|
||||
*/
|
||||
|
||||
void adns__must_gettimeofday(adns_state ads, const struct timeval **now_io,
|
||||
struct timeval *tv_buf);
|
||||
|
||||
int adns__pollfds(adns_state ads, struct pollfd pollfds_buf[MAX_POLLFDS]);
|
||||
void adns__fdevents(adns_state ads,
|
||||
const struct pollfd *pollfds, int npollfds,
|
||||
int maxfd, const fd_set *readfds,
|
||||
const fd_set *writefds, const fd_set *exceptfds,
|
||||
struct timeval now, int *r_r);
|
||||
int adns__internal_check(adns_state ads,
|
||||
adns_query *query_io,
|
||||
adns_answer **answer,
|
||||
void **context_r);
|
||||
|
||||
void adns__timeouts(adns_state ads, int act,
|
||||
struct timeval **tv_io, struct timeval *tvbuf,
|
||||
struct timeval now);
|
||||
/* If act is !0, then this will also deal with the TCP connection
|
||||
* if previous events broke it or require it to be connected.
|
||||
*/
|
||||
|
||||
/* From check.c: */
|
||||
|
||||
void adns__consistency(adns_state ads, adns_query qu, consistency_checks cc);
|
||||
|
||||
/* Useful static inline functions: */
|
||||
|
||||
static inline int ctype_whitespace(int c) { return c==' ' || c=='\n' || c=='\t'; }
|
||||
static inline int ctype_digit(int c) { return c>='0' && c<='9'; }
|
||||
static inline int ctype_alpha(int c) {
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||
}
|
||||
static inline int ctype_822special(int c) { return strchr("()<>@,;:\\\".[]",c) != 0; }
|
||||
static inline int ctype_domainunquoted(int c) {
|
||||
return ctype_alpha(c) || ctype_digit(c) || (strchr("-_/+",c) != 0);
|
||||
}
|
||||
|
||||
static inline int errno_resources(int e) { return e==ENOMEM || e==ENOBUFS; }
|
||||
|
||||
/* Useful macros */
|
||||
|
||||
#define MEM_ROUND(sz) \
|
||||
(( ((sz)+sizeof(union maxalign)-1) / sizeof(union maxalign) ) \
|
||||
* sizeof(union maxalign) )
|
||||
|
||||
#define GETIL_B(cb) (((dgram)[(cb)++]) & 0x0ff)
|
||||
#define GET_B(cb,tv) ((tv)= GETIL_B((cb)))
|
||||
#define GET_W(cb,tv) ((tv)=0, (tv)|=(GETIL_B((cb))<<8), (tv)|=GETIL_B(cb), (tv))
|
||||
#define GET_L(cb,tv) ( (tv)=0, \
|
||||
(tv)|=(GETIL_B((cb))<<24), \
|
||||
(tv)|=(GETIL_B((cb))<<16), \
|
||||
(tv)|=(GETIL_B((cb))<<8), \
|
||||
(tv)|=GETIL_B(cb), \
|
||||
(tv) )
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* parse.c
|
||||
* - parsing assistance functions (mainly for domains inside datagrams)
|
||||
*/
|
||||
/*
|
||||
* This file is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
*
|
||||
* It is part of adns, which is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
* Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef ADNS_JGAA_WIN32
|
||||
# include "adns_win32.h"
|
||||
#endif
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
int vbuf__append_quoted1035(vbuf *vb, const byte *buf, int len) {
|
||||
char qbuf[10];
|
||||
int i, ch;
|
||||
|
||||
while (len) {
|
||||
qbuf[0]= 0;
|
||||
for (i=0; i<len; i++) {
|
||||
ch= buf[i];
|
||||
if (ch <= ' ' || ch >= 127) {
|
||||
sprintf(qbuf,"\\%03o",ch);
|
||||
break;
|
||||
} else if (!ctype_domainunquoted(ch)) {
|
||||
sprintf(qbuf,"\\%c",ch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!adns__vbuf_append(vb,buf,i) || !adns__vbuf_append(vb,qbuf,strlen(qbuf)))
|
||||
return 0;
|
||||
if (i<len) i++;
|
||||
buf+= i;
|
||||
len-= i;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void adns__findlabel_start(findlabel_state *fls, adns_state ads,
|
||||
int serv, adns_query qu,
|
||||
const byte *dgram, int dglen, int max,
|
||||
int dmbegin, int *dmend_rlater) {
|
||||
fls->ads= ads;
|
||||
fls->qu= qu;
|
||||
fls->serv= serv;
|
||||
fls->dgram= dgram;
|
||||
fls->dglen= dglen;
|
||||
fls->max= max;
|
||||
fls->cbyte= dmbegin;
|
||||
fls->namelen= 0;
|
||||
fls->dmend_r= dmend_rlater;
|
||||
}
|
||||
|
||||
adns_status adns__findlabel_next(findlabel_state *fls,
|
||||
int *lablen_r, int *labstart_r) {
|
||||
int lablen, jumpto;
|
||||
const char *dgram;
|
||||
|
||||
dgram= fls->dgram;
|
||||
for (;;) {
|
||||
if (fls->cbyte >= fls->dglen) goto x_truncated;
|
||||
if (fls->cbyte >= fls->max) goto x_badresponse;
|
||||
GET_B(fls->cbyte,lablen);
|
||||
if (!(lablen & 0x0c0)) break;
|
||||
if ((lablen & 0x0c0) != 0x0c0) return adns_s_unknownformat;
|
||||
if (fls->cbyte >= fls->dglen) goto x_truncated;
|
||||
if (fls->cbyte >= fls->max) goto x_badresponse;
|
||||
GET_B(fls->cbyte,jumpto);
|
||||
jumpto |= (lablen&0x3f)<<8;
|
||||
if (fls->dmend_r) *(fls->dmend_r)= fls->cbyte;
|
||||
fls->cbyte= jumpto;
|
||||
fls->dmend_r= 0; fls->max= fls->dglen+1;
|
||||
}
|
||||
if (labstart_r) *labstart_r= fls->cbyte;
|
||||
if (lablen) {
|
||||
if (fls->namelen) fls->namelen++;
|
||||
fls->namelen+= lablen;
|
||||
if (fls->namelen > DNS_MAXDOMAIN) return adns_s_answerdomaintoolong;
|
||||
fls->cbyte+= lablen;
|
||||
if (fls->cbyte > fls->dglen) goto x_truncated;
|
||||
if (fls->cbyte > fls->max) goto x_badresponse;
|
||||
} else {
|
||||
if (fls->dmend_r) *(fls->dmend_r)= fls->cbyte;
|
||||
}
|
||||
*lablen_r= lablen;
|
||||
return adns_s_ok;
|
||||
|
||||
x_truncated:
|
||||
*lablen_r= -1;
|
||||
return adns_s_ok;
|
||||
|
||||
x_badresponse:
|
||||
adns__diag(fls->ads,fls->serv,fls->qu,"label in domain runs beyond end of domain");
|
||||
return adns_s_invalidresponse;
|
||||
}
|
||||
|
||||
adns_status adns__parse_domain(adns_state ads, int serv, adns_query qu,
|
||||
vbuf *vb, adns_queryflags flags,
|
||||
const byte *dgram, int dglen, int *cbyte_io, int max) {
|
||||
findlabel_state fls;
|
||||
|
||||
adns__findlabel_start(&fls,ads, serv,qu, dgram,dglen,max, *cbyte_io,cbyte_io);
|
||||
vb->used= 0;
|
||||
return adns__parse_domain_more(&fls,ads,qu, vb,flags,dgram);
|
||||
}
|
||||
|
||||
adns_status adns__parse_domain_more(findlabel_state *fls, adns_state ads,
|
||||
adns_query qu, vbuf *vb, parsedomain_flags flags,
|
||||
const byte *dgram) {
|
||||
int lablen, labstart, i, ch, first;
|
||||
adns_status st;
|
||||
|
||||
first= 1;
|
||||
for (;;) {
|
||||
st= adns__findlabel_next(fls,&lablen,&labstart);
|
||||
if (st) return st;
|
||||
if (lablen<0) { vb->used=0; return adns_s_ok; }
|
||||
if (!lablen) break;
|
||||
if (first) {
|
||||
first= 0;
|
||||
} else {
|
||||
if (!adns__vbuf_append(vb,".",1)) return adns_s_nomemory;
|
||||
}
|
||||
if (flags & pdf_quoteok) {
|
||||
if (!vbuf__append_quoted1035(vb,dgram+labstart,lablen))
|
||||
return adns_s_nomemory;
|
||||
} else {
|
||||
ch= dgram[labstart];
|
||||
if (!ctype_alpha(ch) && !ctype_digit(ch)) return adns_s_answerdomaininvalid;
|
||||
for (i= labstart+1; i<labstart+lablen; i++) {
|
||||
ch= dgram[i];
|
||||
if (ch != '-' && !ctype_alpha(ch) && !ctype_digit(ch))
|
||||
return adns_s_answerdomaininvalid;
|
||||
}
|
||||
if (!adns__vbuf_append(vb,dgram+labstart,lablen))
|
||||
return adns_s_nomemory;
|
||||
}
|
||||
}
|
||||
if (!adns__vbuf_append(vb,"",1)) return adns_s_nomemory;
|
||||
return adns_s_ok;
|
||||
}
|
||||
|
||||
adns_status adns__findrr_anychk(adns_query qu, int serv,
|
||||
const byte *dgram, int dglen, int *cbyte_io,
|
||||
int *type_r, int *class_r, unsigned long *ttl_r,
|
||||
int *rdlen_r, int *rdstart_r,
|
||||
const byte *eo_dgram, int eo_dglen, int eo_cbyte,
|
||||
int *eo_matched_r) {
|
||||
findlabel_state fls, eo_fls;
|
||||
int cbyte;
|
||||
|
||||
int tmp, rdlen, mismatch;
|
||||
unsigned long ttl;
|
||||
int lablen, labstart, ch;
|
||||
int eo_lablen, eo_labstart, eo_ch;
|
||||
adns_status st;
|
||||
|
||||
cbyte= *cbyte_io;
|
||||
|
||||
adns__findlabel_start(&fls,qu->ads, serv,qu, dgram,dglen,dglen,cbyte,&cbyte);
|
||||
if (eo_dgram) {
|
||||
adns__findlabel_start(&eo_fls,qu->ads, -1,0, eo_dgram,eo_dglen,eo_dglen,eo_cbyte,0);
|
||||
mismatch= 0;
|
||||
} else {
|
||||
mismatch= 1;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
st= adns__findlabel_next(&fls,&lablen,&labstart);
|
||||
if (st) return st;
|
||||
if (lablen<0) goto x_truncated;
|
||||
|
||||
if (!mismatch) {
|
||||
st= adns__findlabel_next(&eo_fls,&eo_lablen,&eo_labstart);
|
||||
assert(!st); assert(eo_lablen>=0);
|
||||
if (lablen != eo_lablen) mismatch= 1;
|
||||
while (!mismatch && eo_lablen-- > 0) {
|
||||
ch= dgram[labstart++]; if (ctype_alpha(ch)) ch &= ~32;
|
||||
eo_ch= eo_dgram[eo_labstart++]; if (ctype_alpha(eo_ch)) eo_ch &= ~32;
|
||||
if (ch != eo_ch) mismatch= 1;
|
||||
}
|
||||
}
|
||||
if (!lablen) break;
|
||||
}
|
||||
if (eo_matched_r) *eo_matched_r= !mismatch;
|
||||
|
||||
if (cbyte+10>dglen) goto x_truncated;
|
||||
GET_W(cbyte,tmp); *type_r= tmp;
|
||||
GET_W(cbyte,tmp); *class_r= tmp;
|
||||
|
||||
GET_L(cbyte,ttl);
|
||||
if (ttl > MAXTTLBELIEVE) ttl= MAXTTLBELIEVE;
|
||||
*ttl_r= ttl;
|
||||
|
||||
GET_W(cbyte,rdlen); if (rdlen_r) *rdlen_r= rdlen;
|
||||
if (rdstart_r) *rdstart_r= cbyte;
|
||||
cbyte+= rdlen;
|
||||
if (cbyte>dglen) goto x_truncated;
|
||||
*cbyte_io= cbyte;
|
||||
return adns_s_ok;
|
||||
|
||||
x_truncated:
|
||||
*type_r= -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
adns_status adns__findrr(adns_query qu, int serv,
|
||||
const byte *dgram, int dglen, int *cbyte_io,
|
||||
int *type_r, int *class_r, unsigned long *ttl_r,
|
||||
int *rdlen_r, int *rdstart_r,
|
||||
int *ownermatchedquery_r) {
|
||||
if (!ownermatchedquery_r) {
|
||||
return adns__findrr_anychk(qu,serv,
|
||||
dgram,dglen,cbyte_io,
|
||||
type_r,class_r,ttl_r,rdlen_r,rdstart_r,
|
||||
0,0,0, 0);
|
||||
} else if (!qu->cname_dgram) {
|
||||
return adns__findrr_anychk(qu,serv,
|
||||
dgram,dglen,cbyte_io,
|
||||
type_r,class_r,ttl_r,rdlen_r,rdstart_r,
|
||||
qu->query_dgram,qu->query_dglen,DNS_HDRSIZE,
|
||||
ownermatchedquery_r);
|
||||
} else {
|
||||
return adns__findrr_anychk(qu,serv,
|
||||
dgram,dglen,cbyte_io,
|
||||
type_r,class_r,ttl_r,rdlen_r,rdstart_r,
|
||||
qu->cname_dgram,qu->cname_dglen,qu->cname_begin,
|
||||
ownermatchedquery_r);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* poll.c
|
||||
* - wrappers for poll(2)
|
||||
*/
|
||||
/*
|
||||
* This file is
|
||||
* Copyright (C) 1997-1999 Ian Jackson <[email protected]>
|
||||
*
|
||||
* It is part of adns, which is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
* Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#ifdef HAVE_POLL
|
||||
|
||||
int adns_beforepoll(adns_state ads, struct pollfd *fds, int *nfds_io, int *timeout_io,
|
||||
const struct timeval *now) {
|
||||
struct timeval tv_nowbuf, tv_tobuf, *tv_to;
|
||||
int space, found, timeout_ms, r;
|
||||
struct pollfd fds_tmp[MAX_POLLFDS];
|
||||
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
|
||||
if (timeout_io) {
|
||||
adns__must_gettimeofday(ads,&now,&tv_nowbuf);
|
||||
if (!now) { *nfds_io= 0; r= 0; goto xit; }
|
||||
|
||||
timeout_ms= *timeout_io;
|
||||
if (timeout_ms == -1) {
|
||||
tv_to= 0;
|
||||
} else {
|
||||
tv_tobuf.tv_sec= timeout_ms / 1000;
|
||||
tv_tobuf.tv_usec= (timeout_ms % 1000)*1000;
|
||||
tv_to= &tv_tobuf;
|
||||
}
|
||||
|
||||
adns__timeouts(ads, 0, &tv_to,&tv_tobuf, *now);
|
||||
|
||||
if (tv_to) {
|
||||
assert(tv_to == &tv_tobuf);
|
||||
timeout_ms= (tv_tobuf.tv_usec+999)/1000;
|
||||
assert(tv_tobuf.tv_sec < (INT_MAX-timeout_ms)/1000);
|
||||
timeout_ms += tv_tobuf.tv_sec*1000;
|
||||
} else {
|
||||
timeout_ms= -1;
|
||||
}
|
||||
*timeout_io= timeout_ms;
|
||||
}
|
||||
|
||||
space= *nfds_io;
|
||||
if (space >= MAX_POLLFDS) {
|
||||
found= adns__pollfds(ads,fds);
|
||||
*nfds_io= found;
|
||||
} else {
|
||||
found= adns__pollfds(ads,fds_tmp);
|
||||
*nfds_io= found;
|
||||
if (space < found) { r= ERANGE; goto xit; }
|
||||
memcpy(fds,fds_tmp,sizeof(struct pollfd)*found);
|
||||
}
|
||||
r= 0;
|
||||
xit:
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
return r;
|
||||
}
|
||||
|
||||
void adns_afterpoll(adns_state ads, const struct pollfd *fds, int nfds,
|
||||
const struct timeval *now) {
|
||||
struct timeval tv_buf;
|
||||
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
adns__must_gettimeofday(ads,&now,&tv_buf);
|
||||
if (now) {
|
||||
adns__timeouts(ads, 1, 0,0, *now);
|
||||
adns__fdevents(ads, fds,nfds, 0,0,0,0, *now,0);
|
||||
}
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
}
|
||||
|
||||
int adns_wait_poll(adns_state ads,
|
||||
adns_query *query_io,
|
||||
adns_answer **answer_r,
|
||||
void **context_r) {
|
||||
int r, nfds, to;
|
||||
struct pollfd fds[MAX_POLLFDS];
|
||||
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
|
||||
for (;;) {
|
||||
r= adns__internal_check(ads,query_io,answer_r,context_r);
|
||||
if (r != EAGAIN) goto xit;
|
||||
nfds= MAX_POLLFDS; to= -1;
|
||||
adns_beforepoll(ads,fds,&nfds,&to,0);
|
||||
r= poll(fds,nfds,to);
|
||||
if (r == -1) {
|
||||
if (errno == EINTR) {
|
||||
if (ads->iflags & adns_if_eintr) { r= EINTR; goto xit; }
|
||||
} else {
|
||||
adns__diag(ads,-1,0,"poll failed in wait: %s",strerror(errno));
|
||||
adns_globalsystemfailure(ads);
|
||||
}
|
||||
} else {
|
||||
assert(r >= 0);
|
||||
adns_afterpoll(ads,fds,nfds,0);
|
||||
}
|
||||
}
|
||||
|
||||
xit:
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
return r;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,573 @@
|
||||
/*
|
||||
* query.c
|
||||
* - overall query management (allocation, completion)
|
||||
* - per-query memory management
|
||||
* - query submission and cancellation (user-visible and internal)
|
||||
*/
|
||||
/*
|
||||
* This file is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
*
|
||||
* It is part of adns, which is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
* Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef ADNS_JGAA_WIN32
|
||||
# include "adns_win32.h"
|
||||
#else
|
||||
# include <stdlib.h>
|
||||
# include <unistd.h>
|
||||
# include <errno.h>
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
static adns_query query_alloc(adns_state ads, const typeinfo *typei,
|
||||
adns_queryflags flags, struct timeval now) {
|
||||
/* Allocate a virgin query and return it. */
|
||||
adns_query qu;
|
||||
|
||||
qu= malloc(sizeof(*qu)); if (!qu) return 0;
|
||||
qu->answer= malloc(sizeof(*qu->answer)); if (!qu->answer) { free(qu); return 0; }
|
||||
|
||||
qu->ads= ads;
|
||||
qu->state= query_tosend;
|
||||
qu->back= qu->next= qu->parent= 0;
|
||||
LIST_INIT(qu->children);
|
||||
LINK_INIT(qu->siblings);
|
||||
LIST_INIT(qu->allocations);
|
||||
qu->interim_allocd= 0;
|
||||
qu->preserved_allocd= 0;
|
||||
qu->final_allocspace= 0;
|
||||
|
||||
qu->typei= typei;
|
||||
qu->query_dgram= 0;
|
||||
qu->query_dglen= 0;
|
||||
adns__vbuf_init(&qu->vb);
|
||||
|
||||
qu->cname_dgram= 0;
|
||||
qu->cname_dglen= qu->cname_begin= 0;
|
||||
|
||||
adns__vbuf_init(&qu->search_vb);
|
||||
qu->search_origlen= qu->search_pos= qu->search_doneabs= 0;
|
||||
|
||||
qu->id= -2; /* will be overwritten with real id before we leave adns */
|
||||
qu->flags= flags;
|
||||
qu->retries= 0;
|
||||
qu->udpnextserver= 0;
|
||||
qu->udpsent= 0;
|
||||
timerclear(&qu->timeout);
|
||||
qu->expires= now.tv_sec + MAXTTLBELIEVE;
|
||||
|
||||
memset(&qu->ctx,0,sizeof(qu->ctx));
|
||||
|
||||
qu->answer->status= adns_s_ok;
|
||||
qu->answer->cname= qu->answer->owner= 0;
|
||||
qu->answer->type= typei->type;
|
||||
qu->answer->expires= -1;
|
||||
qu->answer->nrrs= 0;
|
||||
qu->answer->rrs.untyped= 0;
|
||||
qu->answer->rrsz= typei->rrsz;
|
||||
|
||||
return qu;
|
||||
}
|
||||
|
||||
static void query_submit(adns_state ads, adns_query qu,
|
||||
const typeinfo *typei, vbuf *qumsg_vb, int id,
|
||||
adns_queryflags flags, struct timeval now) {
|
||||
/* Fills in the query message in for a previously-allocated query,
|
||||
* and submits it. Cannot fail. Takes over the memory for qumsg_vb.
|
||||
*/
|
||||
|
||||
qu->vb= *qumsg_vb;
|
||||
adns__vbuf_init(qumsg_vb);
|
||||
|
||||
qu->query_dgram= malloc(qu->vb.used);
|
||||
if (!qu->query_dgram) { adns__query_fail(qu,adns_s_nomemory); return; }
|
||||
|
||||
qu->id= id;
|
||||
qu->query_dglen= qu->vb.used;
|
||||
memcpy(qu->query_dgram,qu->vb.buf,qu->vb.used);
|
||||
|
||||
adns__query_send(qu,now);
|
||||
}
|
||||
|
||||
adns_status adns__internal_submit(adns_state ads, adns_query *query_r,
|
||||
const typeinfo *typei, vbuf *qumsg_vb, int id,
|
||||
adns_queryflags flags, struct timeval now,
|
||||
const qcontext *ctx) {
|
||||
adns_query qu;
|
||||
|
||||
qu= query_alloc(ads,typei,flags,now);
|
||||
if (!qu) { adns__vbuf_free(qumsg_vb); return adns_s_nomemory; }
|
||||
*query_r= qu;
|
||||
|
||||
memcpy(&qu->ctx,ctx,sizeof(qu->ctx));
|
||||
query_submit(ads,qu, typei,qumsg_vb,id,flags,now);
|
||||
|
||||
return adns_s_ok;
|
||||
}
|
||||
|
||||
static void query_simple(adns_state ads, adns_query qu,
|
||||
const char *owner, int ol,
|
||||
const typeinfo *typei, adns_queryflags flags,
|
||||
struct timeval now) {
|
||||
vbuf vb_new;
|
||||
int id;
|
||||
adns_status stat;
|
||||
|
||||
stat= adns__mkquery(ads,&qu->vb,&id, owner,ol, typei,flags);
|
||||
if (stat) {
|
||||
if (stat == adns_s_querydomaintoolong && (flags & adns_qf_search)) {
|
||||
adns__search_next(ads,qu,now);
|
||||
return;
|
||||
} else {
|
||||
adns__query_fail(qu,stat);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
vb_new= qu->vb;
|
||||
adns__vbuf_init(&qu->vb);
|
||||
query_submit(ads,qu, typei,&vb_new,id, flags,now);
|
||||
}
|
||||
|
||||
void adns__search_next(adns_state ads, adns_query qu, struct timeval now) {
|
||||
const char *nextentry;
|
||||
adns_status stat;
|
||||
|
||||
if (qu->search_doneabs<0) {
|
||||
nextentry= 0;
|
||||
qu->search_doneabs= 1;
|
||||
} else {
|
||||
if (qu->search_pos >= ads->nsearchlist) {
|
||||
if (qu->search_doneabs) {
|
||||
stat= adns_s_nxdomain; goto x_fail;
|
||||
return;
|
||||
} else {
|
||||
nextentry= 0;
|
||||
qu->search_doneabs= 1;
|
||||
}
|
||||
} else {
|
||||
nextentry= ads->searchlist[qu->search_pos++];
|
||||
}
|
||||
}
|
||||
|
||||
qu->search_vb.used= qu->search_origlen;
|
||||
if (nextentry) {
|
||||
if (!adns__vbuf_append(&qu->search_vb,".",1) ||
|
||||
!adns__vbuf_appendstr(&qu->search_vb,nextentry)) {
|
||||
stat= adns_s_nomemory; goto x_fail;
|
||||
}
|
||||
}
|
||||
|
||||
free(qu->query_dgram);
|
||||
qu->query_dgram= 0; qu->query_dglen= 0;
|
||||
|
||||
query_simple(ads,qu, qu->search_vb.buf, qu->search_vb.used, qu->typei, qu->flags, now);
|
||||
return;
|
||||
|
||||
x_fail:
|
||||
adns__query_fail(qu,stat);
|
||||
}
|
||||
|
||||
static int save_owner(adns_query qu, const char *owner, int ol) {
|
||||
/* Returns 1 if OK, otherwise there was no memory. */
|
||||
adns_answer *ans;
|
||||
|
||||
ans= qu->answer;
|
||||
assert(!ans->owner);
|
||||
|
||||
ans->owner= adns__alloc_preserved(qu,ol+1); if (!ans->owner) return 0;
|
||||
|
||||
memcpy(ans->owner,owner,ol);
|
||||
ans->owner[ol]= 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int adns_submit(adns_state ads,
|
||||
const char *owner,
|
||||
adns_rrtype type,
|
||||
adns_queryflags flags,
|
||||
void *context,
|
||||
adns_query *query_r) {
|
||||
int r, ol, ndots;
|
||||
adns_status stat;
|
||||
const typeinfo *typei;
|
||||
struct timeval now;
|
||||
adns_query qu;
|
||||
const char *p;
|
||||
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
|
||||
typei= adns__findtype(type);
|
||||
if (!typei) return ENOSYS;
|
||||
|
||||
r= gettimeofday(&now,0); if (r) goto x_errno;
|
||||
qu= query_alloc(ads,typei,flags,now); if (!qu) goto x_errno;
|
||||
|
||||
qu->ctx.ext= context;
|
||||
qu->ctx.callback= 0;
|
||||
memset(&qu->ctx.info,0,sizeof(qu->ctx.info));
|
||||
|
||||
*query_r= qu;
|
||||
|
||||
ol= strlen(owner);
|
||||
if (!ol) { stat= adns_s_querydomaininvalid; goto x_adnsfail; }
|
||||
if (ol>DNS_MAXDOMAIN+1) { stat= adns_s_querydomaintoolong; goto x_adnsfail; }
|
||||
|
||||
if (ol>=1 && owner[ol-1]=='.' && (ol<2 || owner[ol-2]!='\\')) {
|
||||
flags &= ~adns_qf_search;
|
||||
qu->flags= flags;
|
||||
ol--;
|
||||
}
|
||||
|
||||
if (flags & adns_qf_search) {
|
||||
r= adns__vbuf_append(&qu->search_vb,owner,ol);
|
||||
if (!r) { stat= adns_s_nomemory; goto x_adnsfail; }
|
||||
|
||||
for (ndots=0, p=owner; (p= strchr(p,'.')); p++, ndots++);
|
||||
qu->search_doneabs= (ndots >= ads->searchndots) ? -1 : 0;
|
||||
qu->search_origlen= ol;
|
||||
adns__search_next(ads,qu,now);
|
||||
} else {
|
||||
if (flags & adns_qf_owner) {
|
||||
if (!save_owner(qu,owner,ol)) { stat= adns_s_nomemory; goto x_adnsfail; }
|
||||
}
|
||||
query_simple(ads,qu, owner,ol, typei,flags, now);
|
||||
}
|
||||
adns__autosys(ads,now);
|
||||
adns__consistency(ads,qu,cc_entex);
|
||||
return 0;
|
||||
|
||||
x_adnsfail:
|
||||
adns__query_fail(qu,stat);
|
||||
adns__consistency(ads,qu,cc_entex);
|
||||
return 0;
|
||||
|
||||
x_errno:
|
||||
r= errno;
|
||||
assert(r);
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
return r;
|
||||
}
|
||||
|
||||
int adns_submit_reverse_any(adns_state ads,
|
||||
const struct sockaddr *addr,
|
||||
const char *zone,
|
||||
adns_rrtype type,
|
||||
adns_queryflags flags,
|
||||
void *context,
|
||||
adns_query *query_r) {
|
||||
const unsigned char *iaddr;
|
||||
char *buf, *buf_free;
|
||||
char shortbuf[100];
|
||||
int r, lreq;
|
||||
|
||||
flags &= ~adns_qf_search;
|
||||
|
||||
if (addr->sa_family != AF_INET) return ENOSYS;
|
||||
iaddr= (const unsigned char*) &(((const struct sockaddr_in*)addr) -> sin_addr);
|
||||
|
||||
lreq= strlen(zone) + 4*4 + 1;
|
||||
if (lreq > sizeof(shortbuf)) {
|
||||
buf= malloc(strlen(zone) + 4*4 + 1);
|
||||
if (!buf) return errno;
|
||||
buf_free= buf;
|
||||
} else {
|
||||
buf= shortbuf;
|
||||
buf_free= 0;
|
||||
}
|
||||
sprintf(buf, "%d.%d.%d.%d.%s", iaddr[3], iaddr[2], iaddr[1], iaddr[0], zone);
|
||||
|
||||
r= adns_submit(ads,buf,type,flags,context,query_r);
|
||||
free(buf_free);
|
||||
return r;
|
||||
}
|
||||
|
||||
int adns_submit_reverse(adns_state ads,
|
||||
const struct sockaddr *addr,
|
||||
adns_rrtype type,
|
||||
adns_queryflags flags,
|
||||
void *context,
|
||||
adns_query *query_r) {
|
||||
if (type != adns_r_ptr && type != adns_r_ptr_raw) return EINVAL;
|
||||
return adns_submit_reverse_any(ads,addr,"in-addr.arpa",type,flags,context,query_r);
|
||||
}
|
||||
|
||||
int adns_synchronous(adns_state ads,
|
||||
const char *owner,
|
||||
adns_rrtype type,
|
||||
adns_queryflags flags,
|
||||
adns_answer **answer_r) {
|
||||
adns_query qu;
|
||||
int r;
|
||||
|
||||
r= adns_submit(ads,owner,type,flags,0,&qu);
|
||||
if (r) return r;
|
||||
|
||||
r= adns_wait(ads,&qu,answer_r,0);
|
||||
if (r) adns_cancel(qu);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void *alloc_common(adns_query qu, size_t sz) {
|
||||
allocnode *an;
|
||||
|
||||
if (!sz) return qu; /* Any old pointer will do */
|
||||
assert(!qu->final_allocspace);
|
||||
an= malloc(MEM_ROUND(MEM_ROUND(sizeof(*an)) + sz));
|
||||
if (!an) return 0;
|
||||
LIST_LINK_TAIL(qu->allocations,an);
|
||||
return (byte*)an + MEM_ROUND(sizeof(*an));
|
||||
}
|
||||
|
||||
void *adns__alloc_interim(adns_query qu, size_t sz) {
|
||||
void *rv;
|
||||
|
||||
sz= MEM_ROUND(sz);
|
||||
rv= alloc_common(qu,sz);
|
||||
if (!rv) return 0;
|
||||
qu->interim_allocd += sz;
|
||||
return rv;
|
||||
}
|
||||
|
||||
void *adns__alloc_preserved(adns_query qu, size_t sz) {
|
||||
void *rv;
|
||||
|
||||
sz= MEM_ROUND(sz);
|
||||
rv= adns__alloc_interim(qu,sz);
|
||||
if (!rv) return 0;
|
||||
qu->preserved_allocd += sz;
|
||||
return rv;
|
||||
}
|
||||
|
||||
void *adns__alloc_mine(adns_query qu, size_t sz) {
|
||||
return alloc_common(qu,MEM_ROUND(sz));
|
||||
}
|
||||
|
||||
void adns__transfer_interim(adns_query from, adns_query to, void *block, size_t sz) {
|
||||
allocnode *an;
|
||||
|
||||
if (!block) return;
|
||||
an= (void*)((byte*)block - MEM_ROUND(sizeof(*an)));
|
||||
|
||||
assert(!to->final_allocspace);
|
||||
assert(!from->final_allocspace);
|
||||
|
||||
LIST_UNLINK(from->allocations,an);
|
||||
LIST_LINK_TAIL(to->allocations,an);
|
||||
|
||||
sz= MEM_ROUND(sz);
|
||||
from->interim_allocd -= sz;
|
||||
to->interim_allocd += sz;
|
||||
|
||||
if (to->expires > from->expires) to->expires= from->expires;
|
||||
}
|
||||
|
||||
void *adns__alloc_final(adns_query qu, size_t sz) {
|
||||
/* When we're in the _final stage, we _subtract_ from interim_alloc'd
|
||||
* each allocation, and use final_allocspace to point to the next free
|
||||
* bit.
|
||||
*/
|
||||
void *rp;
|
||||
|
||||
sz= MEM_ROUND(sz);
|
||||
rp= qu->final_allocspace;
|
||||
assert(rp);
|
||||
qu->interim_allocd -= sz;
|
||||
assert(qu->interim_allocd>=0);
|
||||
qu->final_allocspace= (byte*)rp + sz;
|
||||
return rp;
|
||||
}
|
||||
|
||||
static void cancel_children(adns_query qu) {
|
||||
adns_query cqu, ncqu;
|
||||
|
||||
for (cqu= qu->children.head; cqu; cqu= ncqu) {
|
||||
ncqu= cqu->siblings.next;
|
||||
adns_cancel(cqu);
|
||||
}
|
||||
}
|
||||
|
||||
void adns__reset_preserved(adns_query qu) {
|
||||
assert(!qu->final_allocspace);
|
||||
cancel_children(qu);
|
||||
qu->answer->nrrs= 0;
|
||||
qu->answer->rrs.untyped= 0;
|
||||
qu->interim_allocd= qu->preserved_allocd;
|
||||
}
|
||||
|
||||
static void free_query_allocs(adns_query qu) {
|
||||
allocnode *an, *ann;
|
||||
|
||||
cancel_children(qu);
|
||||
for (an= qu->allocations.head; an; an= ann) { ann= an->next; free(an); }
|
||||
LIST_INIT(qu->allocations);
|
||||
adns__vbuf_free(&qu->vb);
|
||||
adns__vbuf_free(&qu->search_vb);
|
||||
free(qu->query_dgram);
|
||||
qu->query_dgram= 0;
|
||||
}
|
||||
|
||||
void adns_cancel(adns_query qu) {
|
||||
adns_state ads;
|
||||
|
||||
ads= qu->ads;
|
||||
adns__consistency(ads,qu,cc_entex);
|
||||
if (qu->parent) LIST_UNLINK_PART(qu->parent->children,qu,siblings.);
|
||||
switch (qu->state) {
|
||||
case query_tosend:
|
||||
LIST_UNLINK(ads->udpw,qu);
|
||||
break;
|
||||
case query_tcpw:
|
||||
LIST_UNLINK(ads->tcpw,qu);
|
||||
break;
|
||||
case query_childw:
|
||||
LIST_UNLINK(ads->childw,qu);
|
||||
break;
|
||||
case query_done:
|
||||
LIST_UNLINK(ads->output,qu);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
free_query_allocs(qu);
|
||||
free(qu->answer);
|
||||
free(qu);
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
}
|
||||
|
||||
void adns__update_expires(adns_query qu, unsigned long ttl, struct timeval now) {
|
||||
time_t max;
|
||||
|
||||
assert(ttl <= MAXTTLBELIEVE);
|
||||
max= now.tv_sec + ttl;
|
||||
if (qu->expires < max) return;
|
||||
qu->expires= max;
|
||||
}
|
||||
|
||||
static void makefinal_query(adns_query qu) {
|
||||
adns_answer *ans;
|
||||
int rrn;
|
||||
|
||||
ans= qu->answer;
|
||||
|
||||
if (qu->interim_allocd) {
|
||||
ans= realloc(qu->answer, MEM_ROUND(MEM_ROUND(sizeof(*ans)) + qu->interim_allocd));
|
||||
if (!ans) goto x_nomem;
|
||||
qu->answer= ans;
|
||||
}
|
||||
|
||||
qu->final_allocspace= (byte*)ans + MEM_ROUND(sizeof(*ans));
|
||||
adns__makefinal_str(qu,&ans->cname);
|
||||
adns__makefinal_str(qu,&ans->owner);
|
||||
|
||||
if (ans->nrrs) {
|
||||
adns__makefinal_block(qu, &ans->rrs.untyped, ans->nrrs*ans->rrsz);
|
||||
|
||||
for (rrn=0; rrn<ans->nrrs; rrn++)
|
||||
qu->typei->makefinal(qu, ans->rrs.bytes + rrn*ans->rrsz);
|
||||
}
|
||||
|
||||
free_query_allocs(qu);
|
||||
return;
|
||||
|
||||
x_nomem:
|
||||
qu->preserved_allocd= 0;
|
||||
qu->answer->cname= 0;
|
||||
qu->answer->owner= 0;
|
||||
adns__reset_preserved(qu); /* (but we just threw away the preserved stuff) */
|
||||
|
||||
qu->answer->status= adns_s_nomemory;
|
||||
free_query_allocs(qu);
|
||||
}
|
||||
|
||||
void adns__query_done(adns_query qu) {
|
||||
adns_answer *ans;
|
||||
adns_query parent;
|
||||
|
||||
cancel_children(qu);
|
||||
|
||||
qu->id= -1;
|
||||
ans= qu->answer;
|
||||
|
||||
if (qu->flags & adns_qf_owner && qu->flags & adns_qf_search &&
|
||||
ans->status != adns_s_nomemory) {
|
||||
if (!save_owner(qu, qu->search_vb.buf, qu->search_vb.used)) {
|
||||
adns__query_fail(qu,adns_s_nomemory);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ans->nrrs && qu->typei->diff_needswap) {
|
||||
if (!adns__vbuf_ensure(&qu->vb,qu->typei->rrsz)) {
|
||||
adns__query_fail(qu,adns_s_nomemory);
|
||||
return;
|
||||
}
|
||||
adns__isort(ans->rrs.bytes, ans->nrrs, ans->rrsz,
|
||||
qu->vb.buf,
|
||||
(int(*)(void*, const void*, const void*))qu->typei->diff_needswap,
|
||||
qu->ads);
|
||||
}
|
||||
|
||||
ans->expires= qu->expires;
|
||||
parent= qu->parent;
|
||||
if (parent) {
|
||||
LIST_UNLINK_PART(parent->children,qu,siblings.);
|
||||
LIST_UNLINK(qu->ads->childw,parent);
|
||||
qu->ctx.callback(parent,qu);
|
||||
free_query_allocs(qu);
|
||||
free(qu->answer);
|
||||
free(qu);
|
||||
} else {
|
||||
makefinal_query(qu);
|
||||
LIST_LINK_TAIL(qu->ads->output,qu);
|
||||
qu->state= query_done;
|
||||
}
|
||||
}
|
||||
|
||||
void adns__query_fail(adns_query qu, adns_status stat) {
|
||||
adns__reset_preserved(qu);
|
||||
qu->answer->status= stat;
|
||||
adns__query_done(qu);
|
||||
}
|
||||
|
||||
void adns__makefinal_str(adns_query qu, char **strp) {
|
||||
int l;
|
||||
char *before, *after;
|
||||
|
||||
before= *strp;
|
||||
if (!before) return;
|
||||
l= strlen(before)+1;
|
||||
after= adns__alloc_final(qu,l);
|
||||
memcpy(after,before,l);
|
||||
*strp= after;
|
||||
}
|
||||
|
||||
void adns__makefinal_block(adns_query qu, void **blpp, size_t sz) {
|
||||
void *before, *after;
|
||||
|
||||
before= *blpp;
|
||||
if (!before) return;
|
||||
after= adns__alloc_final(qu,sz);
|
||||
memcpy(after,before,sz);
|
||||
*blpp= after;
|
||||
}
|
||||
@@ -0,0 +1,374 @@
|
||||
/*
|
||||
* reply.c
|
||||
* - main handling and parsing routine for received datagrams
|
||||
*/
|
||||
/*
|
||||
* This file is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
*
|
||||
* It is part of adns, which is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
* Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef ADNS_JGAA_WIN32
|
||||
# include "adns_win32.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
void adns__procdgram(adns_state ads, const byte *dgram, int dglen,
|
||||
int serv, int viatcp, struct timeval now) {
|
||||
int cbyte, rrstart, wantedrrs, rri, foundsoa, foundns, cname_here;
|
||||
int id, f1, f2, qdcount, ancount, nscount, arcount;
|
||||
int flg_ra, flg_rd, flg_tc, flg_qr, opcode;
|
||||
int rrtype, rrclass, rdlength, rdstart;
|
||||
int anstart, nsstart, arstart;
|
||||
int ownermatched, l, nrrs;
|
||||
unsigned long ttl, soattl;
|
||||
const typeinfo *typei;
|
||||
adns_query qu, nqu;
|
||||
dns_rcode rcode;
|
||||
adns_status st;
|
||||
vbuf tempvb;
|
||||
byte *newquery, *rrsdata;
|
||||
parseinfo pai;
|
||||
|
||||
if (dglen<DNS_HDRSIZE) {
|
||||
adns__diag(ads,serv,0,"received datagram too short for message header (%d)",dglen);
|
||||
return;
|
||||
}
|
||||
cbyte= 0;
|
||||
GET_W(cbyte,id);
|
||||
GET_B(cbyte,f1);
|
||||
GET_B(cbyte,f2);
|
||||
GET_W(cbyte,qdcount);
|
||||
GET_W(cbyte,ancount);
|
||||
GET_W(cbyte,nscount);
|
||||
GET_W(cbyte,arcount);
|
||||
assert(cbyte == DNS_HDRSIZE);
|
||||
|
||||
flg_qr= f1&0x80;
|
||||
opcode= (f1&0x78)>>3;
|
||||
flg_tc= f1&0x02;
|
||||
flg_rd= f1&0x01;
|
||||
flg_ra= f2&0x80;
|
||||
rcode= (f2&0x0f);
|
||||
|
||||
cname_here= 0;
|
||||
|
||||
if (!flg_qr) {
|
||||
adns__diag(ads,serv,0,"server sent us a query, not a response");
|
||||
return;
|
||||
}
|
||||
if (opcode) {
|
||||
adns__diag(ads,serv,0,"server sent us unknown opcode %d (wanted 0=QUERY)",opcode);
|
||||
return;
|
||||
}
|
||||
|
||||
qu= 0;
|
||||
/* See if we can find the relevant query, or leave qu=0 otherwise ... */
|
||||
|
||||
if (qdcount == 1) {
|
||||
for (qu= viatcp ? ads->tcpw.head : ads->udpw.head; qu; qu= nqu) {
|
||||
nqu= qu->next;
|
||||
if (qu->id != id) continue;
|
||||
if (dglen < qu->query_dglen) continue;
|
||||
if (memcmp(qu->query_dgram+DNS_HDRSIZE,
|
||||
dgram+DNS_HDRSIZE,
|
||||
qu->query_dglen-DNS_HDRSIZE))
|
||||
continue;
|
||||
if (viatcp) {
|
||||
assert(qu->state == query_tcpw);
|
||||
} else {
|
||||
assert(qu->state == query_tosend);
|
||||
if (!(qu->udpsent & (1<<serv))) continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (qu) {
|
||||
/* We're definitely going to do something with this query now */
|
||||
if (viatcp) LIST_UNLINK(ads->tcpw,qu);
|
||||
else LIST_UNLINK(ads->udpw,qu);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we're going to ignore the packet, we return as soon as we have
|
||||
* failed the query (if any) and printed the warning message (if
|
||||
* any).
|
||||
*/
|
||||
switch (rcode) {
|
||||
case rcode_noerror:
|
||||
case rcode_nxdomain:
|
||||
break;
|
||||
case rcode_formaterror:
|
||||
adns__warn(ads,serv,qu,"server cannot understand our query (Format Error)");
|
||||
if (qu) adns__query_fail(qu,adns_s_rcodeformaterror);
|
||||
return;
|
||||
case rcode_servfail:
|
||||
if (qu) adns__query_fail(qu,adns_s_rcodeservfail);
|
||||
else adns__debug(ads,serv,qu,"server failure on unidentifiable query");
|
||||
return;
|
||||
case rcode_notimp:
|
||||
adns__warn(ads,serv,qu,"server claims not to implement our query");
|
||||
if (qu) adns__query_fail(qu,adns_s_rcodenotimplemented);
|
||||
return;
|
||||
case rcode_refused:
|
||||
adns__debug(ads,serv,qu,"server refused our query");
|
||||
if (qu) adns__query_fail(qu,adns_s_rcoderefused);
|
||||
return;
|
||||
default:
|
||||
adns__warn(ads,serv,qu,"server gave unknown response code %d",rcode);
|
||||
if (qu) adns__query_fail(qu,adns_s_rcodeunknown);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!qu) {
|
||||
if (!qdcount) {
|
||||
adns__diag(ads,serv,0,"server sent reply without quoting our question");
|
||||
} else if (qdcount>1) {
|
||||
adns__diag(ads,serv,0,"server claimed to answer %d questions with one message",
|
||||
qdcount);
|
||||
} else if (ads->iflags & adns_if_debug) {
|
||||
adns__vbuf_init(&tempvb);
|
||||
adns__debug(ads,serv,0,"reply not found, id %02x, query owner %s",
|
||||
id, adns__diag_domain(ads,serv,0,&tempvb,dgram,dglen,DNS_HDRSIZE));
|
||||
adns__vbuf_free(&tempvb);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* We're definitely going to do something with this packet and this query now. */
|
||||
|
||||
anstart= qu->query_dglen;
|
||||
arstart= -1;
|
||||
|
||||
/* Now, take a look at the answer section, and see if it is complete.
|
||||
* If it has any CNAMEs we stuff them in the answer.
|
||||
*/
|
||||
wantedrrs= 0;
|
||||
cbyte= anstart;
|
||||
for (rri= 0; rri<ancount; rri++) {
|
||||
rrstart= cbyte;
|
||||
st= adns__findrr(qu,serv, dgram,dglen,&cbyte,
|
||||
&rrtype,&rrclass,&ttl, &rdlength,&rdstart,
|
||||
&ownermatched);
|
||||
if (st) { adns__query_fail(qu,st); return; }
|
||||
if (rrtype == -1) goto x_truncated;
|
||||
|
||||
if (rrclass != DNS_CLASS_IN) {
|
||||
adns__diag(ads,serv,qu,"ignoring answer RR with wrong class %d (expected IN=%d)",
|
||||
rrclass,DNS_CLASS_IN);
|
||||
continue;
|
||||
}
|
||||
if (!ownermatched) {
|
||||
if (ads->iflags & adns_if_debug) {
|
||||
adns__debug(ads,serv,qu,"ignoring RR with an unexpected owner %s",
|
||||
adns__diag_domain(ads,serv,qu, &qu->vb, dgram,dglen,rrstart));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (rrtype == adns_r_cname &&
|
||||
(qu->typei->type & adns__rrt_typemask) != adns_r_cname) {
|
||||
if (qu->flags & adns_qf_cname_forbid) {
|
||||
adns__query_fail(qu,adns_s_prohibitedcname);
|
||||
return;
|
||||
} else if (qu->cname_dgram) { /* Ignore second and subsequent CNAME(s) */
|
||||
adns__debug(ads,serv,qu,"allegedly canonical name %s is actually alias for %s",
|
||||
qu->answer->cname,
|
||||
adns__diag_domain(ads,serv,qu, &qu->vb, dgram,dglen,rdstart));
|
||||
adns__query_fail(qu,adns_s_prohibitedcname);
|
||||
return;
|
||||
} else if (wantedrrs) { /* Ignore CNAME(s) after RR(s). */
|
||||
adns__debug(ads,serv,qu,"ignoring CNAME (to %s) coexisting with RR",
|
||||
adns__diag_domain(ads,serv,qu, &qu->vb, dgram,dglen,rdstart));
|
||||
} else {
|
||||
qu->cname_begin= rdstart;
|
||||
qu->cname_dglen= dglen;
|
||||
st= adns__parse_domain(ads,serv,qu, &qu->vb,
|
||||
qu->flags & adns_qf_quotefail_cname ? 0 : pdf_quoteok,
|
||||
dgram,dglen, &rdstart,rdstart+rdlength);
|
||||
if (!qu->vb.used) goto x_truncated;
|
||||
if (st) { adns__query_fail(qu,st); return; }
|
||||
l= strlen(qu->vb.buf)+1;
|
||||
qu->answer->cname= adns__alloc_preserved(qu,l);
|
||||
if (!qu->answer->cname) { adns__query_fail(qu,adns_s_nomemory); return; }
|
||||
|
||||
qu->cname_dgram= adns__alloc_mine(qu,dglen);
|
||||
memcpy(qu->cname_dgram,dgram,dglen);
|
||||
|
||||
memcpy(qu->answer->cname,qu->vb.buf,l);
|
||||
cname_here= 1;
|
||||
adns__update_expires(qu,ttl,now);
|
||||
/* If we find the answer section truncated after this point we restart
|
||||
* the query at the CNAME; if beforehand then we obviously have to use
|
||||
* TCP. If there is no truncation we can use the whole answer if
|
||||
* it contains the relevant info.
|
||||
*/
|
||||
}
|
||||
} else if (rrtype == (qu->typei->type & adns__rrt_typemask)) {
|
||||
wantedrrs++;
|
||||
} else {
|
||||
adns__debug(ads,serv,qu,"ignoring answer RR with irrelevant type %d",rrtype);
|
||||
}
|
||||
}
|
||||
|
||||
/* We defer handling truncated responses here, in case there was a CNAME
|
||||
* which we could use.
|
||||
*/
|
||||
if (flg_tc) goto x_truncated;
|
||||
|
||||
nsstart= cbyte;
|
||||
|
||||
if (!wantedrrs) {
|
||||
/* Oops, NODATA or NXDOMAIN or perhaps a referral (which would be a problem) */
|
||||
|
||||
/* RFC2308: NODATA has _either_ a SOA _or_ _no_ NS records in authority section */
|
||||
foundsoa= 0; soattl= 0; foundns= 0;
|
||||
for (rri= 0; rri<nscount; rri++) {
|
||||
rrstart= cbyte;
|
||||
st= adns__findrr(qu,serv, dgram,dglen,&cbyte,
|
||||
&rrtype,&rrclass,&ttl, &rdlength,&rdstart, 0);
|
||||
if (st) { adns__query_fail(qu,st); return; }
|
||||
if (rrtype==-1) goto x_truncated;
|
||||
if (rrclass != DNS_CLASS_IN) {
|
||||
adns__diag(ads,serv,qu,
|
||||
"ignoring authority RR with wrong class %d (expected IN=%d)",
|
||||
rrclass,DNS_CLASS_IN);
|
||||
continue;
|
||||
}
|
||||
if (rrtype == adns_r_soa_raw) { foundsoa= 1; soattl= ttl; break; }
|
||||
else if (rrtype == adns_r_ns_raw) { foundns= 1; }
|
||||
}
|
||||
|
||||
if (rcode == rcode_nxdomain) {
|
||||
/* We still wanted to look for the SOA so we could find the TTL. */
|
||||
adns__update_expires(qu,soattl,now);
|
||||
|
||||
if (qu->flags & adns_qf_search) {
|
||||
adns__search_next(ads,qu,now);
|
||||
} else {
|
||||
adns__query_fail(qu,adns_s_nxdomain);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (foundsoa || !foundns) {
|
||||
/* Aha ! A NODATA response, good. */
|
||||
adns__update_expires(qu,soattl,now);
|
||||
adns__query_fail(qu,adns_s_nodata);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now what ? No relevant answers, no SOA, and at least some NS's.
|
||||
* Looks like a referral. Just one last chance ... if we came across
|
||||
* a CNAME in this datagram then we should probably do our own CNAME
|
||||
* lookup now in the hope that we won't get a referral again.
|
||||
*/
|
||||
if (cname_here) goto x_restartquery;
|
||||
|
||||
/* Bloody hell, I thought we asked for recursion ? */
|
||||
if (!flg_ra) {
|
||||
adns__diag(ads,serv,qu,"server is not willing to do recursive lookups for us");
|
||||
adns__query_fail(qu,adns_s_norecurse);
|
||||
} else {
|
||||
if (!flg_rd)
|
||||
adns__diag(ads,serv,qu,"server thinks we didn't ask for recursive lookup");
|
||||
else
|
||||
adns__debug(ads,serv,qu,"server claims to do recursion, but gave us a referral");
|
||||
adns__query_fail(qu,adns_s_invalidresponse);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now, we have some RRs which we wanted. */
|
||||
|
||||
qu->answer->rrs.untyped= adns__alloc_interim(qu,qu->typei->rrsz*wantedrrs);
|
||||
if (!qu->answer->rrs.untyped) { adns__query_fail(qu,adns_s_nomemory); return; }
|
||||
|
||||
typei= qu->typei;
|
||||
cbyte= anstart;
|
||||
rrsdata= qu->answer->rrs.bytes;
|
||||
|
||||
pai.ads= qu->ads;
|
||||
pai.qu= qu;
|
||||
pai.serv= serv;
|
||||
pai.dgram= dgram;
|
||||
pai.dglen= dglen;
|
||||
pai.nsstart= nsstart;
|
||||
pai.nscount= nscount;
|
||||
pai.arcount= arcount;
|
||||
pai.now= now;
|
||||
|
||||
for (rri=0, nrrs=0; rri<ancount; rri++) {
|
||||
st= adns__findrr(qu,serv, dgram,dglen,&cbyte,
|
||||
&rrtype,&rrclass,&ttl, &rdlength,&rdstart,
|
||||
&ownermatched);
|
||||
assert(!st); assert(rrtype != -1);
|
||||
if (rrclass != DNS_CLASS_IN ||
|
||||
rrtype != (qu->typei->type & adns__rrt_typemask) ||
|
||||
!ownermatched)
|
||||
continue;
|
||||
adns__update_expires(qu,ttl,now);
|
||||
st= typei->parse(&pai, rdstart,rdstart+rdlength, rrsdata+nrrs*typei->rrsz);
|
||||
if (st) { adns__query_fail(qu,st); return; }
|
||||
if (rdstart==-1) goto x_truncated;
|
||||
nrrs++;
|
||||
}
|
||||
assert(nrrs==wantedrrs);
|
||||
qu->answer->nrrs= nrrs;
|
||||
|
||||
/* This may have generated some child queries ... */
|
||||
if (qu->children.head) {
|
||||
qu->state= query_childw;
|
||||
LIST_LINK_TAIL(ads->childw,qu);
|
||||
return;
|
||||
}
|
||||
adns__query_done(qu);
|
||||
return;
|
||||
|
||||
x_truncated:
|
||||
|
||||
if (!flg_tc) {
|
||||
adns__diag(ads,serv,qu,"server sent datagram which points outside itself");
|
||||
adns__query_fail(qu,adns_s_invalidresponse);
|
||||
return;
|
||||
}
|
||||
qu->flags |= adns_qf_usevc;
|
||||
|
||||
x_restartquery:
|
||||
if (qu->cname_dgram) {
|
||||
st= adns__mkquery_frdgram(qu->ads,&qu->vb,&qu->id,
|
||||
qu->cname_dgram, qu->cname_dglen, qu->cname_begin,
|
||||
qu->typei->type, qu->flags);
|
||||
if (st) { adns__query_fail(qu,st); return; }
|
||||
|
||||
newquery= realloc(qu->query_dgram,qu->vb.used);
|
||||
if (!newquery) { adns__query_fail(qu,adns_s_nomemory); return; }
|
||||
|
||||
qu->query_dgram= newquery;
|
||||
qu->query_dglen= qu->vb.used;
|
||||
memcpy(newquery,qu->vb.buf,qu->vb.used);
|
||||
}
|
||||
|
||||
if (qu->state == query_tcpw) qu->state= query_tosend;
|
||||
qu->retries= 0;
|
||||
adns__reset_preserved(qu);
|
||||
adns__query_send(qu,now);
|
||||
}
|
||||
@@ -0,0 +1,732 @@
|
||||
/*
|
||||
* setup.c
|
||||
* - configuration file parsing
|
||||
* - management of global state
|
||||
*/
|
||||
/*
|
||||
* This file is
|
||||
* Copyright (C) 1997-1999 Ian Jackson <[email protected]>
|
||||
*
|
||||
* It is part of adns, which is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
* Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef ADNS_JGAA_WIN32
|
||||
# include "adns_win32.h"
|
||||
# include <iphlpapi.h>
|
||||
#else
|
||||
# include <stdlib.h>
|
||||
# include <errno.h>
|
||||
# include <limits.h>
|
||||
# include <unistd.h>
|
||||
# include <fcntl.h>
|
||||
# include <netdb.h>
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
static void readconfig(adns_state ads, const char *filename, int warnmissing);
|
||||
|
||||
static void addserver(adns_state ads, struct in_addr addr) {
|
||||
int i;
|
||||
struct server *ss;
|
||||
|
||||
for (i=0; i<ads->nservers; i++) {
|
||||
if (ads->servers[i].addr.s_addr == addr.s_addr) {
|
||||
adns__debug(ads,-1,0,"duplicate nameserver %s ignored",inet_ntoa(addr));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ads->nservers>=MAXSERVERS) {
|
||||
adns__diag(ads,-1,0,"too many nameservers, ignoring %s",inet_ntoa(addr));
|
||||
return;
|
||||
}
|
||||
|
||||
ss= ads->servers+ads->nservers;
|
||||
ss->addr= addr;
|
||||
ads->nservers++;
|
||||
}
|
||||
|
||||
static void freesearchlist(adns_state ads) {
|
||||
if (ads->nsearchlist) free(*ads->searchlist);
|
||||
free(ads->searchlist);
|
||||
}
|
||||
|
||||
static void saveerr(adns_state ads, int en) {
|
||||
if (!ads->configerrno) ads->configerrno= en;
|
||||
}
|
||||
|
||||
static void configparseerr(adns_state ads, const char *fn, int lno,
|
||||
const char *fmt, ...) {
|
||||
va_list al;
|
||||
|
||||
saveerr(ads,EINVAL);
|
||||
if (!ads->diagfile || (ads->iflags & adns_if_noerrprint)) return;
|
||||
|
||||
if (lno==-1) fprintf(ads->diagfile,"adns: %s: ",fn);
|
||||
else fprintf(ads->diagfile,"adns: %s:%d: ",fn,lno);
|
||||
va_start(al,fmt);
|
||||
vfprintf(ads->diagfile,fmt,al);
|
||||
va_end(al);
|
||||
fputc('\n',ads->diagfile);
|
||||
}
|
||||
|
||||
static int nextword(const char **bufp_io, const char **word_r, int *l_r) {
|
||||
const char *p, *q;
|
||||
|
||||
p= *bufp_io;
|
||||
while (ctype_whitespace(*p)) p++;
|
||||
if (!*p) return 0;
|
||||
|
||||
q= p;
|
||||
while (*q && !ctype_whitespace(*q)) q++;
|
||||
|
||||
*l_r= q-p;
|
||||
*word_r= p;
|
||||
*bufp_io= q;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void ccf_nameserver(adns_state ads, const char *fn, int lno, const char *buf) {
|
||||
struct in_addr ia;
|
||||
|
||||
if (!inet_aton(buf,&ia)) {
|
||||
configparseerr(ads,fn,lno,"invalid nameserver address `%s'",buf);
|
||||
return;
|
||||
}
|
||||
adns__debug(ads,-1,0,"using nameserver %s",inet_ntoa(ia));
|
||||
addserver(ads,ia);
|
||||
}
|
||||
|
||||
static void ccf_search(adns_state ads, const char *fn, int lno, const char *buf) {
|
||||
const char *bufp, *word;
|
||||
char *newchars, **newptrs, **pp;
|
||||
int count, tl, l;
|
||||
|
||||
if (!buf) return;
|
||||
|
||||
bufp= buf;
|
||||
count= 0;
|
||||
tl= 0;
|
||||
while (nextword(&bufp,&word,&l)) { count++; tl += l+1; }
|
||||
|
||||
newptrs= malloc(sizeof(char*)*count); if (!newptrs) { saveerr(ads,errno); return; }
|
||||
newchars= malloc(tl); if (!newchars) { saveerr(ads,errno); free(newptrs); return; }
|
||||
|
||||
bufp= buf;
|
||||
pp= newptrs;
|
||||
while (nextword(&bufp,&word,&l)) {
|
||||
*pp++= newchars;
|
||||
memcpy(newchars,word,l);
|
||||
newchars += l;
|
||||
*newchars++ = 0;
|
||||
}
|
||||
|
||||
freesearchlist(ads);
|
||||
ads->nsearchlist= count;
|
||||
ads->searchlist= newptrs;
|
||||
}
|
||||
|
||||
static void ccf_sortlist(adns_state ads, const char *fn, int lno, const char *buf) {
|
||||
const char *word;
|
||||
char tbuf[200], *slash, *ep;
|
||||
struct in_addr base, mask;
|
||||
int l;
|
||||
unsigned long initial, baselocal;
|
||||
|
||||
if (!buf) return;
|
||||
|
||||
ads->nsortlist= 0;
|
||||
while (nextword(&buf,&word,&l)) {
|
||||
if (ads->nsortlist >= MAXSORTLIST) {
|
||||
adns__diag(ads,-1,0,"too many sortlist entries, ignoring %.*s onwards",l,word);
|
||||
return;
|
||||
}
|
||||
|
||||
if (l >= sizeof(tbuf)) {
|
||||
configparseerr(ads,fn,lno,"sortlist entry `%.*s' too long",l,word);
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(tbuf,word,l); tbuf[l]= 0;
|
||||
slash= strchr(tbuf,'/');
|
||||
if (slash) *slash++= 0;
|
||||
|
||||
if (!inet_aton(tbuf,&base)) {
|
||||
configparseerr(ads,fn,lno,"invalid address `%s' in sortlist",tbuf);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (slash) {
|
||||
if (strchr(slash,'.')) {
|
||||
if (!inet_aton(slash,&mask)) {
|
||||
configparseerr(ads,fn,lno,"invalid mask `%s' in sortlist",slash);
|
||||
continue;
|
||||
}
|
||||
if (base.s_addr & ~mask.s_addr) {
|
||||
configparseerr(ads,fn,lno,
|
||||
"mask `%s' in sortlist overlaps address `%s'",slash,tbuf);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
initial= strtoul(slash,&ep,10);
|
||||
if (*ep || initial>32) {
|
||||
configparseerr(ads,fn,lno,"mask length `%s' invalid",slash);
|
||||
continue;
|
||||
}
|
||||
mask.s_addr= htonl((0x0ffffffffUL) << (32-initial));
|
||||
}
|
||||
} else {
|
||||
baselocal= ntohl(base.s_addr);
|
||||
if (!baselocal & 0x080000000UL) /* class A */
|
||||
mask.s_addr= htonl(0x0ff000000UL);
|
||||
else if ((baselocal & 0x0c0000000UL) == 0x080000000UL)
|
||||
mask.s_addr= htonl(0x0ffff0000UL); /* class B */
|
||||
else if ((baselocal & 0x0f0000000UL) == 0x0e0000000UL)
|
||||
mask.s_addr= htonl(0x0ff000000UL); /* class C */
|
||||
else {
|
||||
configparseerr(ads,fn,lno,
|
||||
"network address `%s' in sortlist is not in classed ranges,"
|
||||
" must specify mask explicitly", tbuf);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ads->sortlist[ads->nsortlist].base= base;
|
||||
ads->sortlist[ads->nsortlist].mask= mask;
|
||||
ads->nsortlist++;
|
||||
}
|
||||
}
|
||||
|
||||
static void ccf_options(adns_state ads, const char *fn, int lno, const char *buf) {
|
||||
const char *word;
|
||||
char *ep;
|
||||
unsigned long v;
|
||||
int l;
|
||||
|
||||
if (!buf) return;
|
||||
|
||||
while (nextword(&buf,&word,&l)) {
|
||||
if (l==5 && !memcmp(word,"debug",5)) {
|
||||
ads->iflags |= adns_if_debug;
|
||||
continue;
|
||||
}
|
||||
if (l>=6 && !memcmp(word,"ndots:",6)) {
|
||||
v= strtoul(word+6,&ep,10);
|
||||
if (l==6 || ep != word+l || v > INT_MAX) {
|
||||
configparseerr(ads,fn,lno,"option `%.*s' malformed or has bad value",l,word);
|
||||
continue;
|
||||
}
|
||||
ads->searchndots= v;
|
||||
continue;
|
||||
}
|
||||
if (l>=12 && !memcmp(word,"adns_checkc:",12)) {
|
||||
if (!strcmp(word+12,"none")) {
|
||||
ads->iflags &= ~adns_if_checkc_freq;
|
||||
ads->iflags |= adns_if_checkc_entex;
|
||||
} else if (!strcmp(word+12,"entex")) {
|
||||
ads->iflags &= ~adns_if_checkc_freq;
|
||||
ads->iflags |= adns_if_checkc_entex;
|
||||
} else if (!strcmp(word+12,"freq")) {
|
||||
ads->iflags |= adns_if_checkc_freq;
|
||||
} else {
|
||||
configparseerr(ads,fn,lno, "option adns_checkc has bad value `%s' "
|
||||
"(must be none, entex or freq", word+12);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
adns__diag(ads,-1,0,"%s:%d: unknown option `%.*s'", fn,lno, l,word);
|
||||
}
|
||||
}
|
||||
|
||||
static void ccf_clearnss(adns_state ads, const char *fn, int lno, const char *buf) {
|
||||
ads->nservers= 0;
|
||||
}
|
||||
|
||||
static void ccf_include(adns_state ads, const char *fn, int lno, const char *buf) {
|
||||
if (!*buf) {
|
||||
configparseerr(ads,fn,lno,"`include' directive with no filename");
|
||||
return;
|
||||
}
|
||||
readconfig(ads,buf,1);
|
||||
}
|
||||
|
||||
static const struct configcommandinfo {
|
||||
const char *name;
|
||||
void (*fn)(adns_state ads, const char *fn, int lno, const char *buf);
|
||||
} configcommandinfos[]= {
|
||||
{ "nameserver", ccf_nameserver },
|
||||
{ "domain", ccf_search },
|
||||
{ "search", ccf_search },
|
||||
{ "sortlist", ccf_sortlist },
|
||||
{ "options", ccf_options },
|
||||
{ "clearnameservers", ccf_clearnss },
|
||||
{ "include", ccf_include },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
typedef union {
|
||||
FILE *file;
|
||||
const char *text;
|
||||
} getline_ctx;
|
||||
|
||||
static int gl_file(adns_state ads, getline_ctx *src_io, const char *filename,
|
||||
int lno, char *buf, int buflen) {
|
||||
FILE *file= src_io->file;
|
||||
int c, i;
|
||||
char *p;
|
||||
|
||||
p= buf;
|
||||
buflen--;
|
||||
i= 0;
|
||||
|
||||
for (;;) { /* loop over chars */
|
||||
if (i == buflen) {
|
||||
adns__diag(ads,-1,0,"%s:%d: line too long, ignored",filename,lno);
|
||||
goto x_badline;
|
||||
}
|
||||
c= getc(file);
|
||||
if (!c) {
|
||||
adns__diag(ads,-1,0,"%s:%d: line contains nul, ignored",filename,lno);
|
||||
goto x_badline;
|
||||
} else if (c == '\n') {
|
||||
break;
|
||||
} else if (c == EOF) {
|
||||
if (ferror(file)) {
|
||||
saveerr(ads,errno);
|
||||
adns__diag(ads,-1,0,"%s:%d: read error: %s",filename,lno,strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (!i) return -1;
|
||||
break;
|
||||
} else {
|
||||
*p++= c;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
*p++= 0;
|
||||
return i;
|
||||
|
||||
x_badline:
|
||||
saveerr(ads,EINVAL);
|
||||
while ((c= getc(file)) != EOF && c != '\n');
|
||||
return -2;
|
||||
}
|
||||
|
||||
static int gl_text(adns_state ads, getline_ctx *src_io, const char *filename,
|
||||
int lno, char *buf, int buflen) {
|
||||
const char *cp= src_io->text;
|
||||
int l;
|
||||
|
||||
if (!cp || !*cp) return -1;
|
||||
|
||||
if (*cp == ';' || *cp == '\n') cp++;
|
||||
l= strcspn(cp,";\n");
|
||||
src_io->text = cp+l;
|
||||
|
||||
if (l >= buflen) {
|
||||
adns__diag(ads,-1,0,"%s:%d: line too long, ignored",filename,lno);
|
||||
saveerr(ads,EINVAL);
|
||||
return -2;
|
||||
}
|
||||
|
||||
memcpy(buf,cp,l);
|
||||
buf[l]= 0;
|
||||
return l;
|
||||
}
|
||||
|
||||
static void readconfiggeneric(adns_state ads, const char *filename,
|
||||
int (*getline)(adns_state ads, getline_ctx*,
|
||||
const char *filename, int lno,
|
||||
char *buf, int buflen),
|
||||
/* Returns >=0 for success, -1 for EOF or error
|
||||
* (error will have been reported), or -2 for
|
||||
* bad line was encountered, try again.
|
||||
*/
|
||||
getline_ctx gl_ctx) {
|
||||
char linebuf[2000], *p, *q;
|
||||
int lno, l, dirl;
|
||||
const struct configcommandinfo *ccip;
|
||||
|
||||
for (lno=1;
|
||||
(l= getline(ads,&gl_ctx, filename,lno, linebuf,sizeof(linebuf))) != -1;
|
||||
lno++) {
|
||||
if (l == -2) continue;
|
||||
while (l>0 && ctype_whitespace(linebuf[l-1])) l--;
|
||||
linebuf[l]= 0;
|
||||
p= linebuf;
|
||||
while (ctype_whitespace(*p)) p++;
|
||||
if (*p == '#' || !*p) continue;
|
||||
q= p;
|
||||
while (*q && !ctype_whitespace(*q)) q++;
|
||||
dirl= q-p;
|
||||
for (ccip=configcommandinfos;
|
||||
ccip->name && !((int)strlen(ccip->name)==dirl && !memcmp(ccip->name,p,q-p));
|
||||
ccip++);
|
||||
if (!ccip->name) {
|
||||
adns__diag(ads,-1,0,"%s:%d: unknown configuration directive `%.*s'",
|
||||
filename,lno,q-p,p);
|
||||
continue;
|
||||
}
|
||||
while (ctype_whitespace(*q)) q++;
|
||||
ccip->fn(ads,filename,lno,q);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *instrum_getenv(adns_state ads, const char *envvar) {
|
||||
const char *value;
|
||||
|
||||
value= getenv(envvar);
|
||||
if (!value) adns__debug(ads,-1,0,"environment variable %s not set",envvar);
|
||||
else adns__debug(ads,-1,0,"environment variable %s set to `%s'",envvar,value);
|
||||
return value;
|
||||
}
|
||||
|
||||
static void readconfig(adns_state ads, const char *filename, int warnmissing) {
|
||||
getline_ctx gl_ctx;
|
||||
|
||||
gl_ctx.file= fopen(filename,"r");
|
||||
if (!gl_ctx.file) {
|
||||
if (errno == ENOENT) {
|
||||
if (warnmissing)
|
||||
adns__debug(ads,-1,0,"configuration file `%s' does not exist",filename);
|
||||
return;
|
||||
}
|
||||
saveerr(ads,errno);
|
||||
adns__diag(ads,-1,0,"cannot open configuration file `%s': %s",
|
||||
filename,strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
readconfiggeneric(ads,filename,gl_file,gl_ctx);
|
||||
|
||||
fclose(gl_ctx.file);
|
||||
}
|
||||
|
||||
static void readconfigtext(adns_state ads, const char *text, const char *showname) {
|
||||
getline_ctx gl_ctx;
|
||||
|
||||
gl_ctx.text= text;
|
||||
readconfiggeneric(ads,showname,gl_text,gl_ctx);
|
||||
}
|
||||
|
||||
static void readconfigenv(adns_state ads, const char *envvar) {
|
||||
const char *filename;
|
||||
|
||||
if (ads->iflags & adns_if_noenv) {
|
||||
adns__debug(ads,-1,0,"not checking environment variable `%s'",envvar);
|
||||
return;
|
||||
}
|
||||
filename= instrum_getenv(ads,envvar);
|
||||
if (filename) readconfig(ads,filename,1);
|
||||
}
|
||||
|
||||
static void readconfigenvtext(adns_state ads, const char *envvar) {
|
||||
const char *textdata;
|
||||
|
||||
if (ads->iflags & adns_if_noenv) {
|
||||
adns__debug(ads,-1,0,"not checking environment variable `%s'",envvar);
|
||||
return;
|
||||
}
|
||||
textdata= instrum_getenv(ads,envvar);
|
||||
if (textdata) readconfigtext(ads,textdata,envvar);
|
||||
}
|
||||
|
||||
|
||||
int adns__setnonblock(adns_state ads, ADNS_SOCKET fd) {
|
||||
#ifdef ADNS_JGAA_WIN32
|
||||
unsigned long Val = 1;
|
||||
return (ioctlsocket (fd, FIONBIO, &Val) == 0) ? 0 : -1;
|
||||
#else
|
||||
int r;
|
||||
|
||||
r= fcntl(fd,F_GETFL,0); if (r<0) return errno;
|
||||
r |= O_NONBLOCK;
|
||||
r= fcntl(fd,F_SETFL,r); if (r<0) return errno;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int init_begin(adns_state *ads_r, adns_initflags flags, FILE *diagfile) {
|
||||
adns_state ads;
|
||||
|
||||
#ifdef ADNS_JGAA_WIN32
|
||||
WORD wVersionRequested = MAKEWORD( 2, 0 );
|
||||
WSADATA wsaData;
|
||||
int err;
|
||||
#endif
|
||||
|
||||
ads= malloc(sizeof(*ads)); if (!ads) return errno;
|
||||
|
||||
ads->iflags= flags;
|
||||
ads->diagfile= diagfile;
|
||||
ads->configerrno= 0;
|
||||
LIST_INIT(ads->udpw);
|
||||
LIST_INIT(ads->tcpw);
|
||||
LIST_INIT(ads->childw);
|
||||
LIST_INIT(ads->output);
|
||||
ads->forallnext= 0;
|
||||
ads->nextid= 0x311f;
|
||||
ads->udpsocket= ads->tcpsocket= -1;
|
||||
adns__vbuf_init(&ads->tcpsend);
|
||||
adns__vbuf_init(&ads->tcprecv);
|
||||
ads->tcprecv_skip= 0;
|
||||
ads->nservers= ads->nsortlist= ads->nsearchlist= ads->tcpserver= 0;
|
||||
ads->searchndots= 1;
|
||||
ads->tcpstate= server_disconnected;
|
||||
timerclear(&ads->tcptimeout);
|
||||
ads->searchlist= 0;
|
||||
|
||||
#ifdef ADNS_JGAA_WIN32
|
||||
err= WSAStartup( wVersionRequested, &wsaData );
|
||||
if ( err != 0 ) {
|
||||
if (ads->diagfile && ads->iflags & adns_if_debug)
|
||||
fprintf(ads->diagfile,"adns: WSAStartup() failed. \n");
|
||||
return -1;}
|
||||
if (LOBYTE( wsaData.wVersion ) != 2 ||
|
||||
HIBYTE( wsaData.wVersion ) != 0 ) {
|
||||
if (ads->diagfile && ads->iflags & adns_if_debug)
|
||||
fprintf(ads->diagfile,"adns: Need Winsock 2.0 or better!\n");
|
||||
|
||||
WSACleanup();
|
||||
return -1;}
|
||||
|
||||
/* The WinSock DLL is acceptable. Proceed. */
|
||||
#endif
|
||||
|
||||
*ads_r= ads;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_finish(adns_state ads) {
|
||||
struct in_addr ia;
|
||||
struct protoent *proto;
|
||||
int r;
|
||||
|
||||
if (!ads->nservers) {
|
||||
if (ads->diagfile && ads->iflags & adns_if_debug)
|
||||
fprintf(ads->diagfile,"adns: no nameservers, using localhost\n");
|
||||
ia.s_addr= htonl(INADDR_LOOPBACK);
|
||||
addserver(ads,ia);
|
||||
}
|
||||
|
||||
proto= getprotobyname("udp"); if (!proto) { r= ENOPROTOOPT; goto x_free; }
|
||||
ADNS_CLEAR_ERRNO;
|
||||
ads->udpsocket= socket(AF_INET,SOCK_DGRAM,proto->p_proto);
|
||||
ADNS_CAPTURE_ERRNO;
|
||||
if (ads->udpsocket<0) { r= errno; goto x_free; }
|
||||
|
||||
r= adns__setnonblock(ads,ads->udpsocket);
|
||||
if (r) { r= errno; goto x_closeudp; }
|
||||
return 0;
|
||||
|
||||
x_closeudp:
|
||||
adns_socket_close(ads->udpsocket);
|
||||
x_free:
|
||||
free(ads);
|
||||
#ifdef ADNS_JGAA_WIN32
|
||||
WSACleanup();
|
||||
#endif /* WIN32 */
|
||||
return r;
|
||||
}
|
||||
|
||||
static void init_abort(adns_state ads) {
|
||||
if (ads->nsearchlist) {
|
||||
free(ads->searchlist[0]);
|
||||
free(ads->searchlist);
|
||||
}
|
||||
free(ads);
|
||||
#ifdef ADNS_JGAA_WIN32
|
||||
WSACleanup();
|
||||
#endif /* WIN32 */
|
||||
|
||||
}
|
||||
|
||||
int adns_init(adns_state *ads_r, adns_initflags flags, FILE *diagfile) {
|
||||
adns_state ads;
|
||||
const char *res_options, *adns_res_options;
|
||||
int r;
|
||||
#ifdef ADNS_JGAA_WIN32
|
||||
#define SECURE_PATH_LEN (MAX_PATH - 64)
|
||||
char PathBuf[MAX_PATH];
|
||||
struct in_addr addr;
|
||||
#define ADNS_PFIXED_INFO_BLEN (2048)
|
||||
PFIXED_INFO network_info = (PFIXED_INFO)alloca(ADNS_PFIXED_INFO_BLEN);
|
||||
ULONG network_info_blen = ADNS_PFIXED_INFO_BLEN;
|
||||
DWORD network_info_result;
|
||||
PIP_ADDR_STRING pip;
|
||||
const char *network_err_str = "";
|
||||
#endif
|
||||
|
||||
r= init_begin(&ads, flags, diagfile ? diagfile : stderr);
|
||||
if (r) return r;
|
||||
|
||||
res_options= instrum_getenv(ads,"RES_OPTIONS");
|
||||
adns_res_options= instrum_getenv(ads,"ADNS_RES_OPTIONS");
|
||||
ccf_options(ads,"RES_OPTIONS",-1,res_options);
|
||||
ccf_options(ads,"ADNS_RES_OPTIONS",-1,adns_res_options);
|
||||
|
||||
#ifdef ADNS_JGAA_WIN32
|
||||
GetWindowsDirectory(PathBuf, SECURE_PATH_LEN);
|
||||
strcat(PathBuf,"\\resolv.conf");
|
||||
readconfig(ads,PathBuf,1);
|
||||
GetWindowsDirectory(PathBuf, SECURE_PATH_LEN);
|
||||
strcat(PathBuf,"\\resolv-adns.conf");
|
||||
readconfig(ads,PathBuf,0);
|
||||
GetWindowsDirectory(PathBuf, SECURE_PATH_LEN);
|
||||
strcat(PathBuf,"\\System32\\Drivers\\etc\\resolv.conf");
|
||||
readconfig(ads,PathBuf,1);
|
||||
GetWindowsDirectory(PathBuf, SECURE_PATH_LEN);
|
||||
strcat(PathBuf,"\\System32\\Drivers\\etc\\resolv-adns.conf");
|
||||
readconfig(ads,PathBuf,0);
|
||||
network_info_result = GetNetworkParams(network_info, &network_info_blen);
|
||||
if (network_info_result != ERROR_SUCCESS){
|
||||
switch(network_info_result) {
|
||||
case ERROR_BUFFER_OVERFLOW: network_err_str = "ERROR_BUFFER_OVERFLOW"; break;
|
||||
case ERROR_INVALID_PARAMETER: network_err_str = "ERROR_INVALID_PARAMETER"; break;
|
||||
case ERROR_NO_DATA: network_err_str = "ERROR_NO_DATA"; break;
|
||||
case ERROR_NOT_SUPPORTED: network_err_str = "ERROR_NOT_SUPPORTED"; break;}
|
||||
adns__diag(ads,-1,0,"GetNetworkParams() failed with error [%d] %s",
|
||||
network_info_result,network_err_str);
|
||||
}
|
||||
else {
|
||||
for(pip = &(network_info->DnsServerList); pip; pip = pip->Next) {
|
||||
addr.s_addr = inet_addr(pip->IpAddress.String);
|
||||
if ((addr.s_addr != INADDR_ANY) && (addr.s_addr != INADDR_NONE))
|
||||
addserver(ads, addr);
|
||||
}
|
||||
}
|
||||
#else
|
||||
readconfig(ads,"/etc/resolv.conf",1);
|
||||
readconfig(ads,"/etc/resolv-adns.conf",0);
|
||||
#endif
|
||||
|
||||
readconfigenv(ads,"RES_CONF");
|
||||
readconfigenv(ads,"ADNS_RES_CONF");
|
||||
|
||||
readconfigenvtext(ads,"RES_CONF_TEXT");
|
||||
readconfigenvtext(ads,"ADNS_RES_CONF_TEXT");
|
||||
|
||||
ccf_options(ads,"RES_OPTIONS",-1,res_options);
|
||||
ccf_options(ads,"ADNS_RES_OPTIONS",-1,adns_res_options);
|
||||
|
||||
ccf_search(ads,"LOCALDOMAIN",-1,instrum_getenv(ads,"LOCALDOMAIN"));
|
||||
ccf_search(ads,"ADNS_LOCALDOMAIN",-1,instrum_getenv(ads,"ADNS_LOCALDOMAIN"));
|
||||
|
||||
if (ads->configerrno && ads->configerrno != EINVAL) {
|
||||
r= ads->configerrno;
|
||||
init_abort(ads);
|
||||
return r;
|
||||
}
|
||||
|
||||
r= init_finish(ads);
|
||||
if (r) return r;
|
||||
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
*ads_r= ads;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int adns_init_strcfg(adns_state *ads_r, adns_initflags flags,
|
||||
FILE *diagfile, const char *configtext) {
|
||||
adns_state ads;
|
||||
int r;
|
||||
|
||||
r= init_begin(&ads, flags, diagfile); if (r) return r;
|
||||
|
||||
readconfigtext(ads,configtext,"<supplied configuration text>");
|
||||
if (ads->configerrno) {
|
||||
r= ads->configerrno;
|
||||
init_abort(ads);
|
||||
return r;
|
||||
}
|
||||
|
||||
r= init_finish(ads); if (r) return r;
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
*ads_r= ads;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void adns_finish(adns_state ads) {
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
for (;;) {
|
||||
if (ads->udpw.head) adns_cancel(ads->udpw.head);
|
||||
else if (ads->tcpw.head) adns_cancel(ads->tcpw.head);
|
||||
else if (ads->childw.head) adns_cancel(ads->childw.head);
|
||||
else if (ads->output.head) adns_cancel(ads->output.head);
|
||||
else break;
|
||||
}
|
||||
adns_socket_close(ads->udpsocket);
|
||||
if (ads->tcpsocket >= 0) adns_socket_close(ads->tcpsocket);
|
||||
adns__vbuf_free(&ads->tcpsend);
|
||||
adns__vbuf_free(&ads->tcprecv);
|
||||
freesearchlist(ads);
|
||||
free(ads);
|
||||
#ifdef ADNS_JGAA_WIN32
|
||||
WSACleanup();
|
||||
#endif /* WIN32 */
|
||||
|
||||
}
|
||||
|
||||
void adns_forallqueries_begin(adns_state ads) {
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
ads->forallnext=
|
||||
ads->udpw.head ? ads->udpw.head :
|
||||
ads->tcpw.head ? ads->tcpw.head :
|
||||
ads->childw.head ? ads->childw.head :
|
||||
ads->output.head;
|
||||
}
|
||||
|
||||
adns_query adns_forallqueries_next(adns_state ads, void **context_r) {
|
||||
adns_query qu, nqu;
|
||||
|
||||
adns__consistency(ads,0,cc_entex);
|
||||
nqu= ads->forallnext;
|
||||
for (;;) {
|
||||
qu= nqu;
|
||||
if (!qu) return 0;
|
||||
if (qu->next) {
|
||||
nqu= qu->next;
|
||||
} else if (qu == ads->udpw.tail) {
|
||||
nqu=
|
||||
ads->tcpw.head ? ads->tcpw.head :
|
||||
ads->childw.head ? ads->childw.head :
|
||||
ads->output.head;
|
||||
} else if (qu == ads->tcpw.tail) {
|
||||
nqu=
|
||||
ads->childw.head ? ads->childw.head :
|
||||
ads->output.head;
|
||||
} else if (qu == ads->childw.tail) {
|
||||
nqu= ads->output.head;
|
||||
} else {
|
||||
nqu= 0;
|
||||
}
|
||||
if (!qu->parent) break;
|
||||
}
|
||||
ads->forallnext= nqu;
|
||||
if (context_r) *context_r= qu->ctx.ext;
|
||||
return qu;
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* transmit.c
|
||||
* - construct queries
|
||||
* - send queries
|
||||
*/
|
||||
/*
|
||||
* This file is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
*
|
||||
* It is part of adns, which is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
* Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef ADNS_JGAA_WIN32
|
||||
# include "adns_win32.h"
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
# include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#include "internal.h"
|
||||
#include "tvarith.h"
|
||||
|
||||
#define MKQUERY_START(vb) (rqp= (vb)->buf+(vb)->used)
|
||||
#define MKQUERY_ADDB(b) *rqp++= (b)
|
||||
#define MKQUERY_ADDW(w) (MKQUERY_ADDB(((w)>>8)&0x0ff), MKQUERY_ADDB((w)&0x0ff))
|
||||
#define MKQUERY_STOP(vb) ((vb)->used= rqp-(vb)->buf)
|
||||
|
||||
static adns_status mkquery_header(adns_state ads, vbuf *vb, int *id_r, int qdlen) {
|
||||
int id;
|
||||
byte *rqp;
|
||||
|
||||
if (!adns__vbuf_ensure(vb,DNS_HDRSIZE+qdlen+4)) return adns_s_nomemory;
|
||||
|
||||
vb->used= 0;
|
||||
MKQUERY_START(vb);
|
||||
|
||||
*id_r= id= (ads->nextid++) & 0x0ffff;
|
||||
MKQUERY_ADDW(id);
|
||||
MKQUERY_ADDB(0x01); /* QR=Q(0), OPCODE=QUERY(0000), !AA, !TC, RD */
|
||||
MKQUERY_ADDB(0x00); /* !RA, Z=000, RCODE=NOERROR(0000) */
|
||||
MKQUERY_ADDW(1); /* QDCOUNT=1 */
|
||||
MKQUERY_ADDW(0); /* ANCOUNT=0 */
|
||||
MKQUERY_ADDW(0); /* NSCOUNT=0 */
|
||||
MKQUERY_ADDW(0); /* ARCOUNT=0 */
|
||||
|
||||
MKQUERY_STOP(vb);
|
||||
|
||||
return adns_s_ok;
|
||||
}
|
||||
|
||||
static adns_status mkquery_footer(vbuf *vb, adns_rrtype type) {
|
||||
byte *rqp;
|
||||
|
||||
MKQUERY_START(vb);
|
||||
MKQUERY_ADDW(type & adns__rrt_typemask); /* QTYPE */
|
||||
MKQUERY_ADDW(DNS_CLASS_IN); /* QCLASS=IN */
|
||||
MKQUERY_STOP(vb);
|
||||
assert(vb->used <= vb->avail);
|
||||
|
||||
return adns_s_ok;
|
||||
}
|
||||
|
||||
adns_status adns__mkquery(adns_state ads, vbuf *vb, int *id_r,
|
||||
const char *owner, int ol,
|
||||
const typeinfo *typei, adns_queryflags flags) {
|
||||
int ll, c, nbytes;
|
||||
byte label[255], *rqp;
|
||||
const char *p, *pe;
|
||||
adns_status st;
|
||||
|
||||
st= mkquery_header(ads,vb,id_r,ol+2); if (st) return st;
|
||||
|
||||
MKQUERY_START(vb);
|
||||
|
||||
p= owner; pe= owner+ol;
|
||||
nbytes= 0;
|
||||
while (p!=pe) {
|
||||
ll= 0;
|
||||
while (p!=pe && (c= *p++)!='.') {
|
||||
if (c=='\\') {
|
||||
if (!(flags & adns_qf_quoteok_query)) return adns_s_querydomaininvalid;
|
||||
if (ctype_digit(p[0])) {
|
||||
if (ctype_digit(p[1]) && ctype_digit(p[2])) {
|
||||
c= (*p++ - '0')*100 + (*p++ - '0')*10 + (*p++ - '0');
|
||||
if (c >= 256) return adns_s_querydomaininvalid;
|
||||
} else {
|
||||
return adns_s_querydomaininvalid;
|
||||
}
|
||||
} else if (!(c= *p++)) {
|
||||
return adns_s_querydomaininvalid;
|
||||
}
|
||||
}
|
||||
if (!(flags & adns_qf_quoteok_query)) {
|
||||
if (c == '-') {
|
||||
if (!ll) return adns_s_querydomaininvalid;
|
||||
} else if (!ctype_alpha(c) && !ctype_digit(c)) {
|
||||
return adns_s_querydomaininvalid;
|
||||
}
|
||||
}
|
||||
if (ll == sizeof(label)) return adns_s_querydomaininvalid;
|
||||
label[ll++]= c;
|
||||
}
|
||||
if (!ll) return adns_s_querydomaininvalid;
|
||||
if (ll > DNS_MAXLABEL) return adns_s_querydomaintoolong;
|
||||
nbytes+= ll+1;
|
||||
if (nbytes >= DNS_MAXDOMAIN) return adns_s_querydomaintoolong;
|
||||
MKQUERY_ADDB(ll);
|
||||
memcpy(rqp,label,ll); rqp+= ll;
|
||||
}
|
||||
MKQUERY_ADDB(0);
|
||||
|
||||
MKQUERY_STOP(vb);
|
||||
|
||||
st= mkquery_footer(vb,typei->type);
|
||||
|
||||
return adns_s_ok;
|
||||
}
|
||||
|
||||
adns_status adns__mkquery_frdgram(adns_state ads, vbuf *vb, int *id_r,
|
||||
const byte *qd_dgram, int qd_dglen, int qd_begin,
|
||||
adns_rrtype type, adns_queryflags flags) {
|
||||
byte *rqp;
|
||||
findlabel_state fls;
|
||||
int lablen, labstart;
|
||||
adns_status st;
|
||||
|
||||
st= mkquery_header(ads,vb,id_r,qd_dglen); if (st) return st;
|
||||
|
||||
MKQUERY_START(vb);
|
||||
|
||||
adns__findlabel_start(&fls,ads,-1,0,qd_dgram,qd_dglen,qd_dglen,qd_begin,0);
|
||||
for (;;) {
|
||||
st= adns__findlabel_next(&fls,&lablen,&labstart); assert(!st);
|
||||
if (!lablen) break;
|
||||
assert(lablen<255);
|
||||
MKQUERY_ADDB(lablen);
|
||||
memcpy(rqp,qd_dgram+labstart,lablen);
|
||||
rqp+= lablen;
|
||||
}
|
||||
MKQUERY_ADDB(0);
|
||||
|
||||
MKQUERY_STOP(vb);
|
||||
|
||||
st= mkquery_footer(vb,type);
|
||||
|
||||
return adns_s_ok;
|
||||
}
|
||||
|
||||
void adns__querysend_tcp(adns_query qu, struct timeval now) {
|
||||
byte length[2];
|
||||
struct iovec iov[2];
|
||||
int wr, r;
|
||||
adns_state ads;
|
||||
|
||||
if (qu->ads->tcpstate != server_ok) return;
|
||||
|
||||
assert(qu->state == query_tcpw);
|
||||
|
||||
length[0]= (qu->query_dglen&0x0ff00U) >>8;
|
||||
length[1]= (qu->query_dglen&0x0ff);
|
||||
|
||||
ads= qu->ads;
|
||||
if (!adns__vbuf_ensure(&ads->tcpsend,ads->tcpsend.used+qu->query_dglen+2)) return;
|
||||
|
||||
qu->retries++;
|
||||
|
||||
/* Reset idle timeout. */
|
||||
ads->tcptimeout.tv_sec= ads->tcptimeout.tv_usec= 0;
|
||||
|
||||
if (ads->tcpsend.used) {
|
||||
wr= 0;
|
||||
} else {
|
||||
iov[0].iov_base= length;
|
||||
iov[0].iov_len= 2;
|
||||
iov[1].iov_base= qu->query_dgram;
|
||||
iov[1].iov_len= qu->query_dglen;
|
||||
adns__sigpipe_protect(qu->ads);
|
||||
wr= writev(qu->ads->tcpsocket,iov,2);
|
||||
adns__sigpipe_unprotect(qu->ads);
|
||||
if (wr < 0) {
|
||||
if (!(errno == EAGAIN || errno == EINTR || errno == ENOSPC ||
|
||||
errno == ENOBUFS || errno == ENOMEM)) {
|
||||
adns__tcp_broken(ads,"write",strerror(errno));
|
||||
return;
|
||||
}
|
||||
wr= 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (wr<2) {
|
||||
r= adns__vbuf_append(&ads->tcpsend,length,2-wr); assert(r);
|
||||
wr= 0;
|
||||
} else {
|
||||
wr-= 2;
|
||||
}
|
||||
if (wr<qu->query_dglen) {
|
||||
r= adns__vbuf_append(&ads->tcpsend,qu->query_dgram+wr,qu->query_dglen-wr); assert(r);
|
||||
}
|
||||
}
|
||||
|
||||
static void query_usetcp(adns_query qu, struct timeval now) {
|
||||
qu->state= query_tcpw;
|
||||
qu->timeout= now;
|
||||
timevaladd(&qu->timeout,TCPWAITMS);
|
||||
LIST_LINK_TAIL(qu->ads->tcpw,qu);
|
||||
adns__querysend_tcp(qu,now);
|
||||
adns__tcp_tryconnect(qu->ads,now);
|
||||
}
|
||||
|
||||
void adns__query_send(adns_query qu, struct timeval now) {
|
||||
struct sockaddr_in servaddr;
|
||||
int serv, r;
|
||||
adns_state ads;
|
||||
|
||||
assert(qu->state == query_tosend);
|
||||
if ((qu->flags & adns_qf_usevc) || (qu->query_dglen > DNS_MAXUDP)) {
|
||||
query_usetcp(qu,now);
|
||||
return;
|
||||
}
|
||||
|
||||
if (qu->retries >= UDPMAXRETRIES) {
|
||||
adns__query_fail(qu,adns_s_timeout);
|
||||
return;
|
||||
}
|
||||
|
||||
serv= qu->udpnextserver;
|
||||
memset(&servaddr,0,sizeof(servaddr));
|
||||
|
||||
ads= qu->ads;
|
||||
servaddr.sin_family= AF_INET;
|
||||
servaddr.sin_addr= ads->servers[serv].addr;
|
||||
servaddr.sin_port= htons(DNS_PORT);
|
||||
|
||||
ADNS_CLEAR_ERRNO;
|
||||
r= sendto(ads->udpsocket,qu->query_dgram,qu->query_dglen,0,
|
||||
(const struct sockaddr*)&servaddr,sizeof(servaddr));
|
||||
ADNS_CAPTURE_ERRNO;
|
||||
if (r<0 && errno == EMSGSIZE) { qu->retries= 0; query_usetcp(qu,now); return; }
|
||||
if (r<0 && errno != EAGAIN) adns__warn(ads,serv,0,"sendto failed: %s (%d)",strerror(errno), errno);
|
||||
|
||||
qu->timeout= now;
|
||||
timevaladd(&qu->timeout,UDPRETRYMS);
|
||||
qu->udpsent |= (1<<serv);
|
||||
qu->udpnextserver= (serv+1)%ads->nservers;
|
||||
qu->retries++;
|
||||
LIST_LINK_TAIL(ads->udpw,qu);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* tvarith.h
|
||||
* - static inline functions for doing arithmetic on timevals
|
||||
*/
|
||||
/*
|
||||
* This file is
|
||||
* Copyright (C) 1997-1999 Ian Jackson <[email protected]>
|
||||
*
|
||||
* It is part of adns, which is
|
||||
* Copyright (C) 1997-2000 Ian Jackson <[email protected]>
|
||||
* Copyright (C) 1999-2000 Tony Finch <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef ADNS_TVARITH_H_INCLUDED
|
||||
#define ADNS_TVARITH_H_INCLUDED
|
||||
|
||||
static inline void timevaladd(struct timeval *tv_io, long ms) {
|
||||
struct timeval tmp;
|
||||
assert(ms>=0);
|
||||
tmp= *tv_io;
|
||||
tmp.tv_usec += (ms%1000)*1000;
|
||||
tmp.tv_sec += ms/1000;
|
||||
if (tmp.tv_usec >= 1000000) { tmp.tv_sec++; tmp.tv_usec -= 1000000; }
|
||||
*tv_io= tmp;
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user