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:
Art Yerkes
2003-12-18 10:48:20 +00:00
parent 47ff6dc9eb
commit c411b4045f
49 changed files with 11602 additions and 0 deletions
+340
View File
@@ -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.
+122
View File
@@ -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:
+130
View File
@@ -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:
+29
View File
@@ -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
+77
View File
@@ -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
+167
View File
@@ -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/
+222
View File
@@ -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>
+11
View File
@@ -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.
+120
View File
@@ -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
+70
View File
@@ -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])
])
])
])
+39
View File
@@ -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 */
+161
View File
@@ -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 */
+64
View File
@@ -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 */
}
+21
View File
@@ -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 */
+12
View File
@@ -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
+284
View File
@@ -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:
+82
View File
@@ -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)
+272
View File
@@ -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);
}
+361
View File
@@ -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();
}
}
+315
View File
@@ -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);
}
+125
View File
@@ -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
+313
View File
@@ -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;
}
+477
View File
@@ -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);
}
+346
View File
@@ -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);
}
+52
View File
@@ -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
+89
View File
@@ -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;
}
+147
View File
@@ -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
)
+54
View File
@@ -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):
+250
View File
@@ -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
+76
View File
@@ -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)
+48
View File
@@ -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
+859
View File
@@ -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
+25
View File
@@ -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
+225
View File
@@ -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");
}
}
}
+106
View File
@@ -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
+105
View File
@@ -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
+53
View File
@@ -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
+743
View File
@@ -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;
}
+369
View File
@@ -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
}
+721
View File
@@ -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
+250
View File
@@ -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);
}
}
+131
View File
@@ -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
+573
View File
@@ -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;
}
+374
View File
@@ -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);
}
+732
View File
@@ -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;
}
+265
View File
@@ -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);
}
+41
View File
@@ -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