r2991 - in udns: branches/upstream/trunk
branches/upstream/trunk/debian tags/upstream
tags/upstream/0.0.9pre tags/upstream/0.0.9pre/debian
mikma at minisip.org
mikma at minisip.org
Wed Dec 6 13:57:22 CET 2006
Author: mikma
Date: 2006-12-06 13:57:21 +0100 (Wed, 06 Dec 2006)
New Revision: 2991
Added:
udns/branches/upstream/trunk/NOTES
udns/branches/upstream/trunk/udns_rr_naptr.c
udns/tags/upstream/0.0.9pre/
udns/tags/upstream/0.0.9pre/NOTES
udns/tags/upstream/0.0.9pre/udns_rr_naptr.c
Modified:
udns/branches/upstream/trunk/Makefile
udns/branches/upstream/trunk/TODO
udns/branches/upstream/trunk/debian/changelog
udns/branches/upstream/trunk/debian/rules
udns/branches/upstream/trunk/dnsget.c
udns/branches/upstream/trunk/udns.3
udns/branches/upstream/trunk/udns.h
udns/branches/upstream/trunk/udns_dn.c
udns/branches/upstream/trunk/udns_resolver.c
udns/branches/upstream/trunk/udns_rr_txt.c
udns/tags/upstream/0.0.9pre/Makefile
udns/tags/upstream/0.0.9pre/TODO
udns/tags/upstream/0.0.9pre/debian/changelog
udns/tags/upstream/0.0.9pre/debian/rules
udns/tags/upstream/0.0.9pre/dnsget.c
udns/tags/upstream/0.0.9pre/udns.3
udns/tags/upstream/0.0.9pre/udns.h
udns/tags/upstream/0.0.9pre/udns_dn.c
udns/tags/upstream/0.0.9pre/udns_resolver.c
udns/tags/upstream/0.0.9pre/udns_rr_txt.c
Log:
Add udns upstream pre release 0.0.9pre
Modified: udns/branches/upstream/trunk/Makefile
===================================================================
--- udns/branches/upstream/trunk/Makefile 2006-12-06 12:49:32 UTC (rev 2990)
+++ udns/branches/upstream/trunk/Makefile 2006-12-06 12:57:21 UTC (rev 2991)
@@ -1,5 +1,5 @@
#! /usr/bin/make -rf
-# $Id: Makefile,v 1.38 2005/09/12 12:09:10 mjt Exp $
+# $Id: Makefile,v 1.42 2006/11/29 21:27:01 mjt Exp $
# libudns Makefile
#
# Copyright (C) 2005 Michael Tokarev <mjt at corpit.ru>
@@ -20,13 +20,14 @@
# write to the Free Software Foundation, Inc., 59 Temple Place,
# Suite 330, Boston, MA 02111-1307 USA
-VERS = 0.0.8
+VERS = 0.0.9pre
SRCS = udns_dn.c udns_dntosp.c udns_parse.c udns_resolver.c udns_misc.c \
udns_rr_a.c udns_rr_ptr.c udns_rr_mx.c udns_rr_txt.c udns_bl.c \
- udns_rr_srv.c udns_codes.c
+ udns_rr_srv.c udns_rr_naptr.c udns_codes.c
USRCS = dnsget.c rblcheck.c ex-rdns.c
+DEB = debian/copyright debian/changelog debian/control debian/rules
DIST = COPYING.LGPL udns.h udns.3 dnsget.1 rblcheck.1 $(SRCS) $(USRCS) \
- Makefile TODO
+ Makefile TODO NOTES
OBJS = $(SRCS:.c=.o) $(GEN:.c=.o)
LIB = libudns.a
@@ -114,9 +115,10 @@
mv $@.tmp $@
dist: $(NAMEPFX).tar.gz
-$(NAMEPFX).tar.gz: $(DIST)
- mkdir $(NAMEPFX)
+$(NAMEPFX).tar.gz: $(DIST) $(DEB)
+ mkdir $(NAMEPFX) $(NAMEPFX)/debian
ln $(DIST) $(NAMEPFX)
+ ln $(DEB) $(NAMEPFX)/debian
tar cvfz $@ $(NAMEPFX)
rm -rf $(NAMEPFX)
subdist:
Added: udns/branches/upstream/trunk/NOTES
===================================================================
--- udns/branches/upstream/trunk/NOTES 2006-12-06 12:49:32 UTC (rev 2990)
+++ udns/branches/upstream/trunk/NOTES 2006-12-06 12:57:21 UTC (rev 2991)
@@ -0,0 +1,193 @@
+Assorted notes about udns (library).
+
+UDP-only mode
+~~~~~~~~~~~~~
+
+First of all, since udns is (currently) UDP-only, there are some
+shortcomings.
+
+It assumes that a reply will fit into a UDP buffer. With adoption of EDNS0,
+and general robustness of IP stacks, in most cases it's not an issue. But
+in some cases there may be problems:
+
+ - if an RRset is "very large" so it does not fit even in buffer of size
+ requested by the library (current default is 4096; some servers limits
+ it further), we will not see the reply, or will only see "damaged"
+ reply (depending on the server)
+
+ - many DNS servers ignores EDNS0 option requests. In this case, no matter
+ which buffer size udns library will request, such servers reply is limited
+ to 512 bytes (standard pre-EDNS0 DNS packet size).
+
+ - some DNS servers, notable the ones used by Verisign for certain top-level
+ domains, chokes on EDNS0-enabled queries, returning FORMERR. Such
+ behavior isn't prohibited by DNS standards, but in my opinion it's at
+ least weird - the server can easily ignore EDNS0 options and send a
+ reply, instead of sending error.
+ Currently, udns does nothing in this situation, completely ignoring the
+ error returned by the server, and continue waiting for reply. It probably
+ should grok that this server does not understand EDNS0 and retry w/o the
+ options, but it does not. The end result - esp. if your local DNS
+ server or - worse - broken firewall which inspects DNS packets and drops
+ the ones which - from its point of view - are "broken" - is that you
+ see only TEMPFAIL errors from the library trying to resolve ANY names.
+
+Implementing TCP mode (together with non-EDNS0 fall-back as above) isn't
+difficult, but it complicates API significantly. Currently udns uses only
+single UDP socket (or - maybe in the future - two, see below), but in case of
+TCP, it will need to open and close sockets for TCP connections left and
+right, and that have to be integrated into an application's event loop in
+an easy and efficient way. Plus all the timeouts - different for connect(),
+write, and several stages of read.
+
+IPv6 vs IPv4 usage
+~~~~~~~~~~~~~~~~~~
+
+This is only relevant for nameservers reachable over IPv6, NOT for IPv6
+queries. I.e., if you've IPv6 addresses in 'nameservers' line in your
+/etc/resolv.conf file. Even more: if you have BOTH IPv6 AND IPv4 addresses
+there. Or pass them to udns initialization routines.
+
+Since udns uses a single UDP socket to communicate with all nameservers,
+it should support both v4 and v6 communications. Most current platforms
+supports this mode - using PF_INET6 socket and V4MAPPED addresses, i.e,
+"tunnelling" IPv4 inside IPv6. But not all systems supports this. And
+more, it has been said that such mode is deprecated.
+
+So, list only IPv4 or only IPv6 addresses, but don't mix them, in your
+/etc/resolv.conf.
+
+An alternative is to use two sockets instead of 1 - one for IPv6 and one
+for IPv4. For now I'm not sure if it's worth the complexity - again, of
+the API, not the library itself (but this will not simplify library either).
+
+Single socket for all queries
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Using single UDP socket for sending queries to all nameservers has obvious
+advantages. First it's, again, trivial, simple to use API. And simple
+library too. Also, after sending queries to all nameservers (in case first
+didn't reply in time), we will be able to receive late reply from first
+nameserver and accept it.
+
+But this mode has disadvantages too. Most important is that it's much easier
+to send fake reply to us, as the UDP port where we expects the reply to come
+to is constant during the whole lifetime of an application. More secure
+implementations uses random port for every single query. While port number
+(16 bits integer) can not hold much randomness, it's still of some help.
+Ok, udns is a stub resolver, so it expects sorta friendly environment, but
+on LAN it's usually much easier to fire an attack, due to the speed of local
+network, where a bad guy can generate alot of packets in a short time.
+
+Choosing of DNS QueryID
+~~~~~~~~~~~~~~~~~~~~~~~
+
+This is more a TODO item really. Currently, udns uses sequential number for
+query IDs. Which simplifies attacks even more (c.f. the previous item about
+single UDP port), making them nearly trivial. The library should use random
+number for query ID. But there's no portable way to get random numbers, even
+on various flavors of Unix. It's possible to use low bits from tv_nsec field
+returned by gettimeofday() (current time, nanoseconds), but I wrote the library
+in a way to avoid making system calls where possible, because many syscalls
+means many context switches and slow processes as a result. Maybe use some
+application-supplied callback to get random values will be a better way,
+defaulting to gettimeofday() method.
+
+Note that a single query - even if (re)sent to different nameservers, several
+times (due to no reply received in time), uses the same qID assigned when it
+was first dispatched. So we have: single UDP socket (fixed port number),
+sequential (= trivially predictable) qIDs, and long lifetime of those qIDs.
+This all makes (local) attacks against the library really trivial.
+
+Assumptions about RRs returned
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Currently udns processes records in the reply it received sequentially.
+This means that order of the records is significant. For example, if
+we asked for foo.bar A, but the server returned that foo.bar is a CNAME
+(alias) for bar.baz, and bar.baz, in turn, has address 1.2.3.4, when
+the CNAME should come first in reply, followed by A. While DNS specs
+does not say anything about order of records - it's an rrSET - unordered, -
+I think an implementation which returns the records in "wrong" order is
+somewhat insane... Well ok, to be fair, I don't really remember how
+udns handles this now - need to check this in source... ;)
+
+CNAME recursion
+~~~~~~~~~~~~~~~
+
+Another dark point of udns is the handling of CNAMEs returned as replies
+to non-CNAME queries. If we asked for foo.bar A, but it's a CNAME, udns
+expects BOTH the CNAME itself and the target DN to be present in the reply.
+In other words, udns DOES NOT RECURSE CNAMES. If we asked for foo.bar A,
+but only record in reply was that foo.bar is a CNAME for bar.baz, udns will
+return no records to an application (NXDOMAIN). Strictly speaking, udns
+should repeat the query asking for bar.baz A, and recurse. But since it's
+stub resolver, recursive resolver should recurse for us instead.
+
+It's not very difficult to implement, however. Probably with some (global?)
+flag to en/dis-able the feature. Provided there's some demand for it.
+
+To clarify: udns handles CNAME recursion in a single reply packet just fine.
+
+Error reporting
+~~~~~~~~~~~~~~~
+
+Too many places in the code (various failure paths) sets generic "TEMPFAIL"
+error condition. For example, if no nameserver replied to our query, an
+application will get generic TEMPFAIL, instead of something like TIMEDOUT.
+This probably should be fixed, but most applications don't care about the
+exact reasons of failure - 4 common cases are already too much:
+ - query returned some valid data
+ - NXDOMAIN
+ - valid domain but no data of requested type - =NXDOMAIN in most cases
+ - temporary error - this one sometimes (incorrectly!) treated as NXDOMAIN
+ by (naive) applications.
+DNS isn't yes/no, it's at least 3 variants, temp err being the 3rd important
+case! And adding more variations for the temp error case is complicating things
+even more - again, from an application writer standpoint. For diagnostics,
+such more specific error cases are of good help.
+
+Planned API changes
+~~~~~~~~~~~~~~~~~~~
+
+At least one thing I want to change for 0.1 version is a way how queries are
+submitted.
+
+I want to made dns_query object to be owned by an application. So that instead
+of udns library allocating it for the lifetime of query, it will be pre-
+allocated by an application. This simplifies and enhances query submitting
+interface, and complicates it a bit too, in simplest cases.
+
+Currently, we have:
+
+dns_submit_dn(dn, cls, typ, flags, parse, cbck, data)
+dns_submit_p(name, cls, typ, flags, parse, cbck, data)
+dns_submit_a4(ctx, name, flags, cbck, data)
+
+and so on -- with many parameters missed for type-specific cases, but generic
+cases being too complex for most common usage.
+
+Instead, with dns_query being owned by an app, we will be able to separately
+set up various parts of the query - domain name (various forms), type&class,
+parser, flags, callback... and even change them at runtime. And we will also
+be able to reuse query structures, instead of allocating/freeing them every
+time. So the whole thing will look something like:
+
+ q = dns_alloc_query();
+ dns_submit(dns_q_flags(dns_q_a4(q, name, cbck), DNS_F_NOSRCH), data);
+
+The idea is to have a set of functions accepting struct dns_query* and
+returning it (so the calls can be "nested" like the above), to set up
+relevant parts of the query - specific type of callback, conversion from
+(type-specific) query parameters into a domain name (this is for type-
+specific query initializers), and setting various flags and options and
+type&class things.
+
+One example where this is almost essential - if we want to support
+per-query set of nameservers (which isn't at all useless: imagine a
+high-volume mail server, were we want to direct DNSBL queries to a separate
+set of nameservers, and rDNS queries to their own set and so on). Adding
+another argument (set of nameservers to use) to EVERY query submitting
+routine is.. insane. Especially since in 99% cases it will be set to
+default NULL. But with such "nesting" of query initializers, it becomes
+trivial.
Modified: udns/branches/upstream/trunk/TODO
===================================================================
--- udns/branches/upstream/trunk/TODO 2006-12-06 12:49:32 UTC (rev 2990)
+++ udns/branches/upstream/trunk/TODO 2006-12-06 12:57:21 UTC (rev 2991)
@@ -2,6 +2,15 @@
The following is mostly an internal, not user-visible stuff.
+* rearrange an API to make dns_query object owned by application,
+ so that it'll look like this:
+ struct dns_query *q;
+ q = udns_query_alloc(ctx);
+ udns_query_set(q, options, domain_name, flags, ...);
+ udns_query_submit(ctx, q);
+ or
+ udns_query_resolve(ctx, q);
+
* allow NULL callbacks? Or provide separate resolver
context list of queries which are done but wich did not
have callback, and dns_pick() routine to retrieve results
@@ -26,6 +35,23 @@
* dns_init(do_open) - make the parameter opposite, aka
dns_init(skip_open) ?
+* for the above. Use separate routine for initializing the context
+ from system files, to not link stuff reading resolv.conf if it's
+ not needed. So that automatic init will not be possible.
+
+* allow TCP queue?
+
+* detect servers which don't understand EDNS0 (returning FORMERR),
+ and fall back to pre-EDNS0 for them.
+
+* for the above to work, we have to be able to find query object by
+ only ID, not ID + qdn.
+
+* And oh, qID should really be random.
+
+* more accurate error reporting. Currently, udns always returns TEMPFAIL,
+ but don't specify why it happened (ENOMEM, timeout, etc).
+
* check the error value returned by recvfrom() and
sendto() and determine which errors to ignore.
Modified: udns/branches/upstream/trunk/debian/changelog
===================================================================
--- udns/branches/upstream/trunk/debian/changelog 2006-12-06 12:49:32 UTC (rev 2990)
+++ udns/branches/upstream/trunk/debian/changelog 2006-12-06 12:57:21 UTC (rev 2991)
@@ -1,3 +1,25 @@
+udns (0.0.9pre) unstable; urgency=low
+
+ * s/EOVERFLOW/ENFILE, partly to make win32 happy
+
+ * several win32 fixes
+
+ * don't use `class' in udns.h, to make C++ happy
+ (thanks Markus Koetter for pointing this out)
+
+ * fixed CNAME handling in dnsget tool. Another Thank You! goes
+ to Markus Koetter.
+
+ * NAPTR (RFC3403) support, thanks to Mikael Magnusson
+ <mikma at users.sourceforge.net> for this.
+
+ * more Win32 fixes from Mikael Magnusson. I have to admit
+ I never tried to compile it on Win32.
+
+ * added NOTES file
+
+ -- Michael Tokarev <mjt at corpit.ru> Wed, 29 Nov 2006 04:16:21 +0300
+
udns (0.0.8) unstable; urgency=low
* don't compare sockaddr_in's, but individual parts only
Modified: udns/branches/upstream/trunk/debian/rules
===================================================================
--- udns/branches/upstream/trunk/debian/rules 2006-12-06 12:49:32 UTC (rev 2990)
+++ udns/branches/upstream/trunk/debian/rules 2006-12-06 12:57:21 UTC (rev 2991)
@@ -62,7 +62,7 @@
dh_install -plibudns-dev libudns.a libudns.so usr/lib
dh_install -plibudns-dev udns.h usr/include
dh_installman -plibudns-dev udns.3
- dh_installdocs -plibudns-dev TODO
+ dh_installdocs -plibudns-dev TODO NOTES
dh_installexamples -plibudns-dev ex-rdns.c
# udns-utils
Modified: udns/branches/upstream/trunk/dnsget.c
===================================================================
--- udns/branches/upstream/trunk/dnsget.c 2006-12-06 12:49:32 UTC (rev 2990)
+++ udns/branches/upstream/trunk/dnsget.c 2006-12-06 12:57:21 UTC (rev 2991)
@@ -1,4 +1,4 @@
-/* $Id: dnsget.c,v 1.18 2005/05/16 12:43:26 mjt Exp $
+/* $Id: dnsget.c,v 1.22 2006/11/29 21:28:49 mjt Exp $
simple host/dig-like application using UDNS library
Copyright (C) 2005 Michael Tokarev <mjt at corpit.ru>
@@ -203,7 +203,7 @@
case DNS_T_AAAA:
if (rr->dnsrr_dsz != 16) goto xperr;
- printf("%s", inet_ntop(AF_INET6, dptr, dn, DNS_MAXDN));
+ printf("%s", inet_ntop(AF_INET6, dptr, (char*)dn, DNS_MAXDN));
break;
case DNS_T_MX:
@@ -262,6 +262,25 @@
dns_dntosp(dn));
break;
+ case DNS_T_NAPTR: /* order pref flags serv regexp repl */
+ c = dptr;
+ c += 4; /* order, pref */
+ for (n = 0; n < 3; ++n)
+ if (c >= dend) goto xperr;
+ else c += *c + 1;
+ if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) goto xperr;
+ c = dptr;
+ printf("%u %u", dns_get16(c+0), dns_get16(c+2));
+ c += 4;
+ for(n = 0; n < 3; ++n) {
+ putchar(' ');
+ if (verbose > 0) putchar('"');
+ c = printtxt(c);
+ if (verbose > 0) putchar('"');
+ }
+ printf(" %s.", dns_dntosp(dn));
+ break;
+
case DNS_T_KEY: /* flags(2) proto(1) algo(1) pubkey */
c = dptr;
if (c + 2 + 1 + 1 > dend) goto xperr;
@@ -466,7 +485,7 @@
struct dns_rr rr;
unsigned nrr;
unsigned char dn[DNS_MAXDN];
- const unsigned char *pkt, *cur, *end, *qdn;
+ const unsigned char *pkt, *cur, *end;
if (!result) {
dnserror(q, r);
return;
@@ -475,10 +494,9 @@
dns_getdn(pkt, &cur, end, dn, sizeof(dn));
dns_initparse(&p, NULL, pkt, cur, end);
p.dnsp_qcls = p.dnsp_qtyp = 0;
- qdn = dn;
nrr = 0;
while((r = dns_nextrr(&p, &rr)) > 0) {
- if (!dns_dnequal(qdn, rr.dnsrr_dn)) continue;
+ if (!dns_dnequal(dn, rr.dnsrr_dn)) continue;
if ((qcls == DNS_C_ANY || qcls == rr.dnsrr_cls) &&
(q->qtyp == DNS_T_ANY || q->qtyp == rr.dnsrr_typ))
++nrr;
@@ -491,10 +509,10 @@
}
else {
if (verbose == 1) {
- printf("%s.", dns_dntosp(qdn));
+ printf("%s.", dns_dntosp(dn));
printf(" CNAME %s.\n", dns_dntosp(p.dnsp_dnbuf));
}
- qdn = p.dnsp_dnbuf;
+ dns_dntodn(p.dnsp_dnbuf, dn, sizeof(dn));
}
}
}
Modified: udns/branches/upstream/trunk/udns.3
===================================================================
--- udns/branches/upstream/trunk/udns.3 2006-12-06 12:49:32 UTC (rev 2990)
+++ udns/branches/upstream/trunk/udns.3 2006-12-06 12:57:21 UTC (rev 2991)
@@ -1,4 +1,4 @@
-.\" $Id: udns.3,v 1.25 2005/09/12 12:05:12 mjt Exp $
+.\" $Id: udns.3,v 1.26 2006/11/28 22:58:04 mjt Exp $
.\" udns library manpage
.\"
.\" Copyright (C) 2005 Michael Tokarev <mjt at corpit.ru>
@@ -810,6 +810,48 @@
interest (if the \fIname\fR is absolute, that is, it ends up with a dot,
DNS_NOSRCH flag will be set automatically).
+.SS "NAPTR Queries"
+.PP
+.nf
+struct \fBdns_naptr\fR { /* single NAPTR record */
+ int \fBorder\fR; /* record order */
+ int \fBpreference\fR; /* preference of this record */
+ char *\fBflags\fR; /* application-specific flags */
+ char *\fBservices\fR; /* service parameters */
+ char *\fBregexp\fR; /* substitutional regular expression */
+ char *\fBreplacement\fR; /* replacement string */
+};
+struct \fBdns_rr_naptr\fR { /* NAPTR RRset */
+ char *\fBdnsnaptr_qname\fR; /* original query name */
+ char *\fBdnsnaptr_cname\fR; /* canonical name */
+ unsigned \fBdnsnaptr_ttl\fR; /* Time-To-Live (TTL) value */
+ int \fBdnsnaptr_nrr\fR; /* number of text records in the set */
+ struct dns_naptr \fBdnsnaptr_naptr\fR[]; /* array of NAPTR records */
+};
+typedef void
+ \fBdns_query_naptr_fn\fR(\fIctx\fR, struct dns_rr_naptr *\fIresult\fR, \fIdata\fR)
+dns_parse_fn \fBdns_parse_naptr\fB;
+struct dns_query *
+\fBdns_submit_naptr\fB(\fIctx\fR, const char *\fIname\fR, int \fIflags\fR,
+ dns_query_txt_fn *\fIcbck\fR, \fIdata\fR);
+struct dns_rr_naptr *
+\fBdns_resolve_naptr\fB(\fIctx\fR, const char *\fIname\fR, int \fIflags\fR);
+.fi
+.PP
+The \fBdns_rr_naptr\fR structure holds a result of an IN NAPTR (rfc3403) query.
+Callback routine for IN NAPTR queries expected to be of type
+\fBdns_query_naptr_fn\fR, expects pointer to \fBdns_rr_naptr\fR
+structure as query result instead of raw DNS packet.
+The \fBdns_parse_naptr\fR() is used to convert raw DNS reply packet into
+\fBdns_rr_naptr\fR structure (it is used
+internally and may be used directly too with generic query interface).
+Routines \fBdns_submit_naptr\fR() and \fBdns_resolve_naptr\fR() are used to
+perform IN NAPTR queries in a type-safe manner. The \fIname\fR parameter
+is the domain name in question, and \fIflags\fR is query flags bitmask,
+with one bit, DNS_NOSRCH, of practical interest (if the \fIname\fR is
+absolute, that is, it ends up with a dot, DNS_NOSRCH flag will be set
+automatically).
+
.SS "DNSBL Interface"
.PP
A DNS-based blocklists, or a DNSBLs, are in wide use nowadays, especially
Modified: udns/branches/upstream/trunk/udns.h
===================================================================
--- udns/branches/upstream/trunk/udns.h 2006-12-06 12:49:32 UTC (rev 2990)
+++ udns/branches/upstream/trunk/udns.h 2006-12-06 12:57:21 UTC (rev 2991)
@@ -1,4 +1,4 @@
-/* $Id: udns.h,v 1.37 2005/09/12 12:09:10 mjt Exp $
+/* $Id: udns.h,v 1.41 2006/11/29 01:20:30 mjt Exp $
header file for the UDNS library.
Copyright (C) 2005 Michael Tokarev <mjt at corpit.ru>
@@ -23,7 +23,7 @@
#ifndef UDNS_VERSION /* include guard */
-#define UDNS_VERSION "0.0.8"
+#define UDNS_VERSION "0.0.9pre"
#ifdef WIN32
# ifdef UDNS_DYNAMIC_LIBRARY
@@ -479,8 +479,7 @@
UDNS_API int
dns_cancel(struct dns_ctx *ctx, struct dns_query *q);
-/* immediately resolve a generic query, return the answer
- * and place completion status into *statusp */
+/* resolve a generic query, return the answer */
UDNS_API void *
dns_resolve_dn(struct dns_ctx *ctx,
dnscc_t *qdn, int qcls, int qtyp, int flags,
@@ -636,8 +635,34 @@
const char *name, const char *srv, const char *proto,
int flags);
+/* NAPTR (RFC3403) RR type */
+struct dns_naptr { /* single NAPTR RR */
+ int order; /* NAPTR order */
+ int preference; /* NAPTR preference */
+ char *flags; /* NAPTR flags */
+ char *service; /* NAPTR service */
+ char *regexp; /* NAPTR regexp */
+ char *replacement; /* NAPTR replacement */
+};
+struct dns_rr_naptr { /* the NAPTR RRset */
+ dns_rr_common(dnsnaptr);
+ struct dns_naptr *dnsnaptr_naptr; /* array of NAPTRes */
+};
+UDNS_API dns_parse_fn dns_parse_naptr; /* NAPTR RR parsing routine */
+typedef void /* NAPTR RR callback */
+dns_query_naptr_fn(struct dns_ctx *ctx,
+ struct dns_rr_naptr *result, void *data);
+/* submit NAPTR IN query */
UDNS_API struct dns_query *
+dns_submit_naptr(struct dns_ctx *ctx, const char *name, int flags,
+ dns_query_naptr_fn *cbck, void *data);
+/* resolve NAPTR IN query */
+UDNS_API struct dns_rr_naptr *
+dns_resolve_naptr(struct dns_ctx *ctx, const char *name, int flags);
+
+
+UDNS_API struct dns_query *
dns_submit_a4dnsbl(struct dns_ctx *ctx,
const struct in_addr *addr, const char *dnsbl,
dns_query_a4_fn *cbck, void *data);
@@ -693,11 +718,11 @@
UDNS_DATA_API extern const struct dns_nameval dns_rcodetab[];
UDNS_API int
dns_findname(const struct dns_nameval *nv, const char *name);
-#define dns_findclassname(class) dns_findname(dns_classtab, (class))
+#define dns_findclassname(cls) dns_findname(dns_classtab, (cls))
#define dns_findtypename(type) dns_findname(dns_typetab, (type))
#define dns_findrcodename(rcode) dns_findname(dns_rcodetab, (rcode))
-UDNS_API const char *dns_classname(enum dns_class class);
+UDNS_API const char *dns_classname(enum dns_class cls);
UDNS_API const char *dns_typename(enum dns_type type);
UDNS_API const char *dns_rcodename(enum dns_rcode rcode);
const char *_dns_format_code(char *buf, const char *prefix, int code);
Modified: udns/branches/upstream/trunk/udns_dn.c
===================================================================
--- udns/branches/upstream/trunk/udns_dn.c 2006-12-06 12:49:32 UTC (rev 2990)
+++ udns/branches/upstream/trunk/udns_dn.c 2006-12-06 12:57:21 UTC (rev 2991)
@@ -1,4 +1,4 @@
-/* $Id: udns_dn.c,v 1.6 2005/09/12 10:55:21 mjt Exp $
+/* $Id: udns_dn.c,v 1.7 2006/11/28 22:45:20 mjt Exp $
domain names manipulation routines
Copyright (C) 2005 Michael Tokarev <mjt at corpit.ru>
@@ -71,7 +71,7 @@
dnsc_t *const de /* end of dn: last byte that can be filled up */
= dn + (dnsiz >= DNS_MAXDN ? DNS_MAXDN : dnsiz) - 1;
dnscc_t *np = (dnscc_t *)name;
- dnscc_t *ne = np + (namelen ? namelen : strlen(np));
+ dnscc_t *ne = np + (namelen ? namelen : strlen((char*)np));
dnsc_t *llab; /* start of last label (llab[-1] will be length) */
unsigned c; /* next input character, or length of last label */
Modified: udns/branches/upstream/trunk/udns_resolver.c
===================================================================
--- udns/branches/upstream/trunk/udns_resolver.c 2006-12-06 12:49:32 UTC (rev 2990)
+++ udns/branches/upstream/trunk/udns_resolver.c 2006-12-06 12:57:21 UTC (rev 2991)
@@ -1,4 +1,4 @@
-/* $Id: udns_resolver.c,v 1.53 2005/09/12 10:23:08 mjt Exp $
+/* $Id: udns_resolver.c,v 1.57 2006/11/29 01:17:43 mjt Exp $
resolver stuff (main module)
Copyright (C) 2005 Michael Tokarev <mjt at corpit.ru>
@@ -24,6 +24,8 @@
#ifdef WIN32
# include <winsock2.h> /* includes <windows.h> */
# include <ws2tcpip.h> /* needed for struct in6_addr */
+# include <iphlpapi.h> /* for dns server addresses etc */
+# undef HAVE_POLL
#else
# include <sys/types.h>
# include <sys/socket.h>
@@ -255,7 +257,7 @@
if (!serv)
return (ctx->dnsc_nserv = 0);
if (ctx->dnsc_nserv >= DNS_MAXSERV)
- return errno = EOVERFLOW, -1;
+ return errno = ENFILE, -1;
sns = &ctx->dnsc_serv[ctx->dnsc_nserv];
memset(sns, 0, sizeof(*sns));
#if HAVE_INET6
@@ -301,7 +303,7 @@
if (!sa)
return (ctx->dnsc_nserv = 0);
if (ctx->dnsc_nserv >= DNS_MAXSERV)
- return errno = EOVERFLOW, -1;
+ return errno = ENFILE, -1;
#if HAVE_INET6
else if (sa->sa_family == AF_INET6)
ctx->dnsc_serv[ctx->dnsc_nserv].sin6 = *(struct sockaddr_in6*)sa;
@@ -380,7 +382,7 @@
if (!srch)
return (ctx->dnsc_nsrch = 0);
else if (ctx->dnsc_nsrch >= DNS_MAXSRCH)
- return errno = EOVERFLOW, -1;
+ return errno = ENFILE, -1;
else if (dns_sptodn(srch, ctx->dnsc_srch[ctx->dnsc_nsrch], DNS_MAXDN) <= 0)
return errno = EINVAL, -1;
else
@@ -461,17 +463,17 @@
int ret = -1;
h_iphlpapi = LoadLibrary("iphlpapi.dll");
- if (h_iphlpapi == HANDLE_ERROR)
+ if (!h_iphlpapi)
return -1;
pfnGetAdAddrs = (GetAdaptersAddressesFunc)
- GetProcAddress(iphlp, "GetAdaptersAddresses");
+ GetProcAddress(h_iphlpapi, "GetAdaptersAddresses");
if (!pfnGetAdAddrs) goto freelib;
ulOutBufLen = 0;
- dwRetVal = GetAdAddrs(AF_UNSPEC, 0, NULL, NULL, &ulOutBufLen);
+ dwRetVal = pfnGetAdAddrs(AF_UNSPEC, 0, NULL, NULL, &ulOutBufLen);
if (dwRetVal != ERROR_BUFFER_OVERFLOW) goto freelib;
pAddrBuf = malloc(ulOutBufLen);
if (!pAddrBuf) goto freelib;
- dwRetVal = GetAdAddrs(AF_UNSPEC, 0, NULL, pAddrBuf, &ulOutBufLen);
+ dwRetVal = pfnGetAdAddrs(AF_UNSPEC, 0, NULL, pAddrBuf, &ulOutBufLen);
if (dwRetVal != ERROR_SUCCESS) goto freemem;
for (pAddr = pAddrBuf;
pAddr && ctx->dnsc_nserv <= DNS_MAXSERV;
@@ -507,7 +509,7 @@
res = RegQueryValueEx(hk, "NameServer", NULL, &type, valBuf, &len);
if (res != ERROR_SUCCESS || !len || !valBuf[0]) {
len = sizeof(valBuf) - 1;
- res = RegQueryValueEx(hk, "DhcpNameServer", &type, valBuf, &len);
+ res = RegQueryValueEx(hk, "DhcpNameServer", NULL, &type, valBuf, &len);
}
RegCloseKey(hk);
if (res != ERROR_SUCCESS || !len || !valBuf[0])
@@ -751,7 +753,7 @@
void dns_close(struct dns_ctx *ctx) {
SETCTXINITED(ctx);
if (ctx->dnsc_udpsock < 0) return;
- close(ctx->dnsc_udpsock);
+ closesocket(ctx->dnsc_udpsock);
ctx->dnsc_udpsock = -1;
free(ctx->dnsc_pbuf);
ctx->dnsc_pbuf = NULL;
@@ -1039,7 +1041,7 @@
* remote errors should be ignored (for now anyway).
*/
#ifdef WIN32
- if (WSAGetLastError() != WSAEWOULDBLOCK)
+ if (WSAGetLastError() == WSAEWOULDBLOCK)
#else
if (errno == EAGAIN)
#endif
@@ -1250,9 +1252,6 @@
void *dns_resolve(struct dns_ctx *ctx, struct dns_query *q) {
time_t now;
-#ifdef WIN32
-# warning fixme: poll()/select() on WIN32 (WaitForMultipleObjects?)
-#endif
#ifdef HAVE_POLL
struct pollfd pfd;
#else
Added: udns/branches/upstream/trunk/udns_rr_naptr.c
===================================================================
--- udns/branches/upstream/trunk/udns_rr_naptr.c 2006-12-06 12:49:32 UTC (rev 2990)
+++ udns/branches/upstream/trunk/udns_rr_naptr.c 2006-12-06 12:57:21 UTC (rev 2991)
@@ -0,0 +1,128 @@
+/* $Id: udns_rr_naptr.c,v 1.1 2006/11/28 22:58:04 mjt Exp $
+ parse/query NAPTR IN records
+
+ Copyright (C) 2005 Michael Tokarev <mjt at corpit.ru>
+ Copyright (C) 2006 Mikael Magnusson <mikma at users.sourceforge.net>
+ This file is part of UDNS library, an async DNS stub resolver.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library, in file named COPYING.LGPL; if not,
+ write to the Free Software Foundation, Inc., 59 Temple Place,
+ Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "udns.h"
+
+/* Get a single string for NAPTR record, pretty much like a DN label.
+ * String length is in first byte in *cur, so it can't be >255.
+ */
+static int dns_getstr(dnscc_t **cur, dnscc_t *ep, char *buf)
+{
+ unsigned l;
+ dnscc_t *cp = *cur;
+
+ l = *cp++;
+ if (cp + l > ep)
+ return DNS_E_PROTOCOL;
+ if (buf) {
+ memcpy(buf, cp, l);
+ buf[l] = '\0';
+ }
+ cp += l;
+
+ *cur = cp;
+ return l + 1;
+}
+
+int
+dns_parse_naptr(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end,
+ void **result) {
+ struct dns_rr_naptr *ret;
+ struct dns_parse p;
+ struct dns_rr rr;
+ int r, l;
+ char *sp;
+ dnsc_t dn[DNS_MAXDN];
+
+ assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_NAPTR);
+
+ /* first, validate the answer and count size of the result */
+ l = 0;
+ dns_initparse(&p, qdn, pkt, cur, end);
+ while((r = dns_nextrr(&p, &rr)) > 0) {
+ int i;
+ dnscc_t *ep = rr.dnsrr_dend;
+
+ /* first 4 bytes: order & preference */
+ cur = rr.dnsrr_dptr + 4;
+
+ /* flags, services and regexp */
+ for (i = 0; i < 3; i++) {
+ r = dns_getstr(&cur, ep, NULL);
+ if (r < 0)
+ return r;
+ l += r;
+ }
+ /* replacement */
+ r = dns_getdn(pkt, &cur, end, dn, sizeof(dn));
+ if (r <= 0 || cur != rr.dnsrr_dend)
+ return DNS_E_PROTOCOL;
+ l += dns_dntop_size(dn);
+ }
+ if (r < 0)
+ return DNS_E_PROTOCOL;
+ if (!p.dnsp_nrr)
+ return DNS_E_NODATA;
+
+ /* next, allocate and set up result */
+ l += dns_stdrr_size(&p);
+ ret = malloc(sizeof(*ret) + sizeof(struct dns_naptr) * p.dnsp_nrr + l);
+ if (!ret)
+ return DNS_E_NOMEM;
+ ret->dnsnaptr_nrr = p.dnsp_nrr;
+ ret->dnsnaptr_naptr = (struct dns_naptr *)(ret+1);
+
+ /* and 3rd, fill in result, finally */
+ sp = (char*)(&ret->dnsnaptr_naptr[p.dnsp_nrr]);
+ for (dns_rewind(&p, qdn), r = 0; dns_nextrr(&p, &rr); ++r) {
+ cur = rr.dnsrr_dptr;
+ ret->dnsnaptr_naptr[r].order = dns_get16(cur); cur += 2;
+ ret->dnsnaptr_naptr[r].preference = dns_get16(cur); cur += 2;
+ sp += dns_getstr(&cur, end, (ret->dnsnaptr_naptr[r].flags = sp));
+ sp += dns_getstr(&cur, end, (ret->dnsnaptr_naptr[r].service = sp));
+ sp += dns_getstr(&cur, end, (ret->dnsnaptr_naptr[r].regexp = sp));
+ dns_getdn(pkt, &cur, end, dn, sizeof(dn));
+ sp += dns_dntop(dn, (ret->dnsnaptr_naptr[r].replacement = sp), DNS_MAXNAME);
+ }
+ dns_stdrr_finish((struct dns_rr_null *)ret, sp, &p);
+ *result = ret;
+ return 0;
+}
+
+struct dns_query *
+dns_submit_naptr(struct dns_ctx *ctx, const char *name, int flags,
+ dns_query_naptr_fn *cbck, void *data) {
+ return
+ dns_submit_p(ctx, name, DNS_C_IN, DNS_T_NAPTR, flags,
+ dns_parse_naptr, (dns_query_fn *)cbck, data);
+}
+
+struct dns_rr_naptr *
+dns_resolve_naptr(struct dns_ctx *ctx, const char *name, int flags) {
+ return (struct dns_rr_naptr *)
+ dns_resolve_p(ctx, name, DNS_C_IN, DNS_T_NAPTR, flags, dns_parse_naptr);
+}
Property changes on: udns/branches/upstream/trunk/udns_rr_naptr.c
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Name: svn:eol-style
+ native
Modified: udns/branches/upstream/trunk/udns_rr_txt.c
===================================================================
--- udns/branches/upstream/trunk/udns_rr_txt.c 2006-12-06 12:49:32 UTC (rev 2990)
+++ udns/branches/upstream/trunk/udns_rr_txt.c 2006-12-06 12:57:21 UTC (rev 2991)
@@ -1,4 +1,4 @@
-/* $Id: udns_rr_txt.c,v 1.14 2005/04/20 06:44:34 mjt Exp $
+/* $Id: udns_rr_txt.c,v 1.15 2006/11/28 22:45:20 mjt Exp $
parse/query TXT records
Copyright (C) 2005 Michael Tokarev <mjt at corpit.ru>
@@ -78,7 +78,7 @@
ret->dnstxt_txt[r].len = sp - ret->dnstxt_txt[r].txt;
*sp++ = '\0';
}
- dns_stdrr_finish((struct dns_rr_null *)ret, sp, &p);
+ dns_stdrr_finish((struct dns_rr_null *)ret, (char*)sp, &p);
*result = ret;
return 0;
}
Copied: udns/tags/upstream/0.0.9pre (from rev 2990, udns/branches/upstream/trunk)
Modified: udns/tags/upstream/0.0.9pre/Makefile
===================================================================
--- udns/branches/upstream/trunk/Makefile 2006-12-06 12:49:32 UTC (rev 2990)
+++ udns/tags/upstream/0.0.9pre/Makefile 2006-12-06 12:57:21 UTC (rev 2991)
@@ -1,5 +1,5 @@
#! /usr/bin/make -rf
-# $Id: Makefile,v 1.38 2005/09/12 12:09:10 mjt Exp $
+# $Id: Makefile,v 1.42 2006/11/29 21:27:01 mjt Exp $
# libudns Makefile
#
# Copyright (C) 2005 Michael Tokarev <mjt at corpit.ru>
@@ -20,13 +20,14 @@
# write to the Free Software Foundation, Inc., 59 Temple Place,
# Suite 330, Boston, MA 02111-1307 USA
-VERS = 0.0.8
+VERS = 0.0.9pre
SRCS = udns_dn.c udns_dntosp.c udns_parse.c udns_resolver.c udns_misc.c \
udns_rr_a.c udns_rr_ptr.c udns_rr_mx.c udns_rr_txt.c udns_bl.c \
- udns_rr_srv.c udns_codes.c
+ udns_rr_srv.c udns_rr_naptr.c udns_codes.c
USRCS = dnsget.c rblcheck.c ex-rdns.c
+DEB = debian/copyright debian/changelog debian/control debian/rules
DIST = COPYING.LGPL udns.h udns.3 dnsget.1 rblcheck.1 $(SRCS) $(USRCS) \
- Makefile TODO
+ Makefile TODO NOTES
OBJS = $(SRCS:.c=.o) $(GEN:.c=.o)
LIB = libudns.a
@@ -114,9 +115,10 @@
mv $@.tmp $@
dist: $(NAMEPFX).tar.gz
-$(NAMEPFX).tar.gz: $(DIST)
- mkdir $(NAMEPFX)
+$(NAMEPFX).tar.gz: $(DIST) $(DEB)
+ mkdir $(NAMEPFX) $(NAMEPFX)/debian
ln $(DIST) $(NAMEPFX)
+ ln $(DEB) $(NAMEPFX)/debian
tar cvfz $@ $(NAMEPFX)
rm -rf $(NAMEPFX)
subdist:
Added: udns/tags/upstream/0.0.9pre/NOTES
===================================================================
--- udns/branches/upstream/trunk/NOTES 2006-12-06 12:49:32 UTC (rev 2990)
+++ udns/tags/upstream/0.0.9pre/NOTES 2006-12-06 12:57:21 UTC (rev 2991)
@@ -0,0 +1,193 @@
+Assorted notes about udns (library).
+
+UDP-only mode
+~~~~~~~~~~~~~
+
+First of all, since udns is (currently) UDP-only, there are some
+shortcomings.
+
+It assumes that a reply will fit into a UDP buffer. With adoption of EDNS0,
+and general robustness of IP stacks, in most cases it's not an issue. But
+in some cases there may be problems:
+
+ - if an RRset is "very large" so it does not fit even in buffer of size
+ requested by the library (current default is 4096; some servers limits
+ it further), we will not see the reply, or will only see "damaged"
+ reply (depending on the server)
+
+ - many DNS servers ignores EDNS0 option requests. In this case, no matter
+ which buffer size udns library will request, such servers reply is limited
+ to 512 bytes (standard pre-EDNS0 DNS packet size).
+
+ - some DNS servers, notable the ones used by Verisign for certain top-level
+ domains, chokes on EDNS0-enabled queries, returning FORMERR. Such
+ behavior isn't prohibited by DNS standards, but in my opinion it's at
+ least weird - the server can easily ignore EDNS0 options and send a
+ reply, instead of sending error.
+ Currently, udns does nothing in this situation, completely ignoring the
+ error returned by the server, and continue waiting for reply. It probably
+ should grok that this server does not understand EDNS0 and retry w/o the
+ options, but it does not. The end result - esp. if your local DNS
+ server or - worse - broken firewall which inspects DNS packets and drops
+ the ones which - from its point of view - are "broken" - is that you
+ see only TEMPFAIL errors from the library trying to resolve ANY names.
+
+Implementing TCP mode (together with non-EDNS0 fall-back as above) isn't
+difficult, but it complicates API significantly. Currently udns uses only
+single UDP socket (or - maybe in the future - two, see below), but in case of
+TCP, it will need to open and close sockets for TCP connections left and
+right, and that have to be integrated into an application's event loop in
+an easy and efficient way. Plus all the timeouts - different for connect(),
+write, and several stages of read.
+
+IPv6 vs IPv4 usage
+~~~~~~~~~~~~~~~~~~
+
+This is only relevant for nameservers reachable over IPv6, NOT for IPv6
+queries. I.e., if you've IPv6 addresses in 'nameservers' line in your
+/etc/resolv.conf file. Even more: if you have BOTH IPv6 AND IPv4 addresses
+there. Or pass them to udns initialization routines.
+
+Since udns uses a single UDP socket to communicate with all nameservers,
+it should support both v4 and v6 communications. Most current platforms
+supports this mode - using PF_INET6 socket and V4MAPPED addresses, i.e,
+"tunnelling" IPv4 inside IPv6. But not all systems supports this. And
+more, it has been said that such mode is deprecated.
+
+So, list only IPv4 or only IPv6 addresses, but don't mix them, in your
+/etc/resolv.conf.
+
+An alternative is to use two sockets instead of 1 - one for IPv6 and one
+for IPv4. For now I'm not sure if it's worth the complexity - again, of
+the API, not the library itself (but this will not simplify library either).
+
+Single socket for all queries
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Using single UDP socket for sending queries to all nameservers has obvious
+advantages. First it's, again, trivial, simple to use API. And simple
+library too. Also, after sending queries to all nameservers (in case first
+didn't reply in time), we will be able to receive late reply from first
+nameserver and accept it.
+
+But this mode has disadvantages too. Most important is that it's much easier
+to send fake reply to us, as the UDP port where we expects the reply to come
+to is constant during the whole lifetime of an application. More secure
+implementations uses random port for every single query. While port number
+(16 bits integer) can not hold much randomness, it's still of some help.
+Ok, udns is a stub resolver, so it expects sorta friendly environment, but
+on LAN it's usually much easier to fire an attack, due to the speed of local
+network, where a bad guy can generate alot of packets in a short time.
+
+Choosing of DNS QueryID
+~~~~~~~~~~~~~~~~~~~~~~~
+
+This is more a TODO item really. Currently, udns uses sequential number for
+query IDs. Which simplifies attacks even more (c.f. the previous item about
+single UDP port), making them nearly trivial. The library should use random
+number for query ID. But there's no portable way to get random numbers, even
+on various flavors of Unix. It's possible to use low bits from tv_nsec field
+returned by gettimeofday() (current time, nanoseconds), but I wrote the library
+in a way to avoid making system calls where possible, because many syscalls
+means many context switches and slow processes as a result. Maybe use some
+application-supplied callback to get random values will be a better way,
+defaulting to gettimeofday() method.
+
+Note that a single query - even if (re)sent to different nameservers, several
+times (due to no reply received in time), uses the same qID assigned when it
+was first dispatched. So we have: single UDP socket (fixed port number),
+sequential (= trivially predictable) qIDs, and long lifetime of those qIDs.
+This all makes (local) attacks against the library really trivial.
+
+Assumptions about RRs returned
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Currently udns processes records in the reply it received sequentially.
+This means that order of the records is significant. For example, if
+we asked for foo.bar A, but the server returned that foo.bar is a CNAME
+(alias) for bar.baz, and bar.baz, in turn, has address 1.2.3.4, when
+the CNAME should come first in reply, followed by A. While DNS specs
+does not say anything about order of records - it's an rrSET - unordered, -
+I think an implementation which returns the records in "wrong" order is
+somewhat insane... Well ok, to be fair, I don't really remember how
+udns handles this now - need to check this in source... ;)
+
+CNAME recursion
+~~~~~~~~~~~~~~~
+
+Another dark point of udns is the handling of CNAMEs returned as replies
+to non-CNAME queries. If we asked for foo.bar A, but it's a CNAME, udns
+expects BOTH the CNAME itself and the target DN to be present in the reply.
+In other words, udns DOES NOT RECURSE CNAMES. If we asked for foo.bar A,
+but only record in reply was that foo.bar is a CNAME for bar.baz, udns will
+return no records to an application (NXDOMAIN). Strictly speaking, udns
+should repeat the query asking for bar.baz A, and recurse. But since it's
+stub resolver, recursive resolver should recurse for us instead.
+
+It's not very difficult to implement, however. Probably with some (global?)
+flag to en/dis-able the feature. Provided there's some demand for it.
+
+To clarify: udns handles CNAME recursion in a single reply packet just fine.
+
+Error reporting
+~~~~~~~~~~~~~~~
+
+Too many places in the code (various failure paths) sets generic "TEMPFAIL"
+error condition. For example, if no nameserver replied to our query, an
+application will get generic TEMPFAIL, instead of something like TIMEDOUT.
+This probably should be fixed, but most applications don't care about the
+exact reasons of failure - 4 common cases are already too much:
+ - query returned some valid data
+ - NXDOMAIN
+ - valid domain but no data of requested type - =NXDOMAIN in most cases
+ - temporary error - this one sometimes (incorrectly!) treated as NXDOMAIN
+ by (naive) applications.
+DNS isn't yes/no, it's at least 3 variants, temp err being the 3rd important
+case! And adding more variations for the temp error case is complicating things
+even more - again, from an application writer standpoint. For diagnostics,
+such more specific error cases are of good help.
+
+Planned API changes
+~~~~~~~~~~~~~~~~~~~
+
+At least one thing I want to change for 0.1 version is a way how queries are
+submitted.
+
+I want to made dns_query object to be owned by an application. So that instead
+of udns library allocating it for the lifetime of query, it will be pre-
+allocated by an application. This simplifies and enhances query submitting
+interface, and complicates it a bit too, in simplest cases.
+
+Currently, we have:
+
+dns_submit_dn(dn, cls, typ, flags, parse, cbck, data)
+dns_submit_p(name, cls, typ, flags, parse, cbck, data)
+dns_submit_a4(ctx, name, flags, cbck, data)
+
+and so on -- with many parameters missed for type-specific cases, but generic
+cases being too complex for most common usage.
+
+Instead, with dns_query being owned by an app, we will be able to separately
+set up various parts of the query - domain name (various forms), type&class,
+parser, flags, callback... and even change them at runtime. And we will also
+be able to reuse query structures, instead of allocating/freeing them every
+time. So the whole thing will look something like:
+
+ q = dns_alloc_query();
+ dns_submit(dns_q_flags(dns_q_a4(q, name, cbck), DNS_F_NOSRCH), data);
+
+The idea is to have a set of functions accepting struct dns_query* and
+returning it (so the calls can be "nested" like the above), to set up
+relevant parts of the query - specific type of callback, conversion from
+(type-specific) query parameters into a domain name (this is for type-
+specific query initializers), and setting various flags and options and
+type&class things.
+
+One example where this is almost essential - if we want to support
+per-query set of nameservers (which isn't at all useless: imagine a
+high-volume mail server, were we want to direct DNSBL queries to a separate
+set of nameservers, and rDNS queries to their own set and so on). Adding
+another argument (set of nameservers to use) to EVERY query submitting
+routine is.. insane. Especially since in 99% cases it will be set to
+default NULL. But with such "nesting" of query initializers, it becomes
+trivial.
Modified: udns/tags/upstream/0.0.9pre/TODO
===================================================================
--- udns/branches/upstream/trunk/TODO 2006-12-06 12:49:32 UTC (rev 2990)
+++ udns/tags/upstream/0.0.9pre/TODO 2006-12-06 12:57:21 UTC (rev 2991)
@@ -2,6 +2,15 @@
The following is mostly an internal, not user-visible stuff.
+* rearrange an API to make dns_query object owned by application,
+ so that it'll look like this:
+ struct dns_query *q;
+ q = udns_query_alloc(ctx);
+ udns_query_set(q, options, domain_name, flags, ...);
+ udns_query_submit(ctx, q);
+ or
+ udns_query_resolve(ctx, q);
+
* allow NULL callbacks? Or provide separate resolver
context list of queries which are done but wich did not
have callback, and dns_pick() routine to retrieve results
@@ -26,6 +35,23 @@
* dns_init(do_open) - make the parameter opposite, aka
dns_init(skip_open) ?
+* for the above. Use separate routine for initializing the context
+ from system files, to not link stuff reading resolv.conf if it's
+ not needed. So that automatic init will not be possible.
+
+* allow TCP queue?
+
+* detect servers which don't understand EDNS0 (returning FORMERR),
+ and fall back to pre-EDNS0 for them.
+
+* for the above to work, we have to be able to find query object by
+ only ID, not ID + qdn.
+
+* And oh, qID should really be random.
+
+* more accurate error reporting. Currently, udns always returns TEMPFAIL,
+ but don't specify why it happened (ENOMEM, timeout, etc).
+
* check the error value returned by recvfrom() and
sendto() and determine which errors to ignore.
Modified: udns/tags/upstream/0.0.9pre/debian/changelog
===================================================================
--- udns/branches/upstream/trunk/debian/changelog 2006-12-06 12:49:32 UTC (rev 2990)
+++ udns/tags/upstream/0.0.9pre/debian/changelog 2006-12-06 12:57:21 UTC (rev 2991)
@@ -1,3 +1,25 @@
+udns (0.0.9pre) unstable; urgency=low
+
+ * s/EOVERFLOW/ENFILE, partly to make win32 happy
+
+ * several win32 fixes
+
+ * don't use `class' in udns.h, to make C++ happy
+ (thanks Markus Koetter for pointing this out)
+
+ * fixed CNAME handling in dnsget tool. Another Thank You! goes
+ to Markus Koetter.
+
+ * NAPTR (RFC3403) support, thanks to Mikael Magnusson
+ <mikma at users.sourceforge.net> for this.
+
+ * more Win32 fixes from Mikael Magnusson. I have to admit
+ I never tried to compile it on Win32.
+
+ * added NOTES file
+
+ -- Michael Tokarev <mjt at corpit.ru> Wed, 29 Nov 2006 04:16:21 +0300
+
udns (0.0.8) unstable; urgency=low
* don't compare sockaddr_in's, but individual parts only
Modified: udns/tags/upstream/0.0.9pre/debian/rules
===================================================================
--- udns/branches/upstream/trunk/debian/rules 2006-12-06 12:49:32 UTC (rev 2990)
+++ udns/tags/upstream/0.0.9pre/debian/rules 2006-12-06 12:57:21 UTC (rev 2991)
@@ -62,7 +62,7 @@
dh_install -plibudns-dev libudns.a libudns.so usr/lib
dh_install -plibudns-dev udns.h usr/include
dh_installman -plibudns-dev udns.3
- dh_installdocs -plibudns-dev TODO
+ dh_installdocs -plibudns-dev TODO NOTES
dh_installexamples -plibudns-dev ex-rdns.c
# udns-utils
Modified: udns/tags/upstream/0.0.9pre/dnsget.c
===================================================================
--- udns/branches/upstream/trunk/dnsget.c 2006-12-06 12:49:32 UTC (rev 2990)
+++ udns/tags/upstream/0.0.9pre/dnsget.c 2006-12-06 12:57:21 UTC (rev 2991)
@@ -1,4 +1,4 @@
-/* $Id: dnsget.c,v 1.18 2005/05/16 12:43:26 mjt Exp $
+/* $Id: dnsget.c,v 1.22 2006/11/29 21:28:49 mjt Exp $
simple host/dig-like application using UDNS library
Copyright (C) 2005 Michael Tokarev <mjt at corpit.ru>
@@ -203,7 +203,7 @@
case DNS_T_AAAA:
if (rr->dnsrr_dsz != 16) goto xperr;
- printf("%s", inet_ntop(AF_INET6, dptr, dn, DNS_MAXDN));
+ printf("%s", inet_ntop(AF_INET6, dptr, (char*)dn, DNS_MAXDN));
break;
case DNS_T_MX:
@@ -262,6 +262,25 @@
dns_dntosp(dn));
break;
+ case DNS_T_NAPTR: /* order pref flags serv regexp repl */
+ c = dptr;
+ c += 4; /* order, pref */
+ for (n = 0; n < 3; ++n)
+ if (c >= dend) goto xperr;
+ else c += *c + 1;
+ if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) goto xperr;
+ c = dptr;
+ printf("%u %u", dns_get16(c+0), dns_get16(c+2));
+ c += 4;
+ for(n = 0; n < 3; ++n) {
+ putchar(' ');
+ if (verbose > 0) putchar('"');
+ c = printtxt(c);
+ if (verbose > 0) putchar('"');
+ }
+ printf(" %s.", dns_dntosp(dn));
+ break;
+
case DNS_T_KEY: /* flags(2) proto(1) algo(1) pubkey */
c = dptr;
if (c + 2 + 1 + 1 > dend) goto xperr;
@@ -466,7 +485,7 @@
struct dns_rr rr;
unsigned nrr;
unsigned char dn[DNS_MAXDN];
- const unsigned char *pkt, *cur, *end, *qdn;
+ const unsigned char *pkt, *cur, *end;
if (!result) {
dnserror(q, r);
return;
@@ -475,10 +494,9 @@
dns_getdn(pkt, &cur, end, dn, sizeof(dn));
dns_initparse(&p, NULL, pkt, cur, end);
p.dnsp_qcls = p.dnsp_qtyp = 0;
- qdn = dn;
nrr = 0;
while((r = dns_nextrr(&p, &rr)) > 0) {
- if (!dns_dnequal(qdn, rr.dnsrr_dn)) continue;
+ if (!dns_dnequal(dn, rr.dnsrr_dn)) continue;
if ((qcls == DNS_C_ANY || qcls == rr.dnsrr_cls) &&
(q->qtyp == DNS_T_ANY || q->qtyp == rr.dnsrr_typ))
++nrr;
@@ -491,10 +509,10 @@
}
else {
if (verbose == 1) {
- printf("%s.", dns_dntosp(qdn));
+ printf("%s.", dns_dntosp(dn));
printf(" CNAME %s.\n", dns_dntosp(p.dnsp_dnbuf));
}
- qdn = p.dnsp_dnbuf;
+ dns_dntodn(p.dnsp_dnbuf, dn, sizeof(dn));
}
}
}
Modified: udns/tags/upstream/0.0.9pre/udns.3
===================================================================
--- udns/branches/upstream/trunk/udns.3 2006-12-06 12:49:32 UTC (rev 2990)
+++ udns/tags/upstream/0.0.9pre/udns.3 2006-12-06 12:57:21 UTC (rev 2991)
@@ -1,4 +1,4 @@
-.\" $Id: udns.3,v 1.25 2005/09/12 12:05:12 mjt Exp $
+.\" $Id: udns.3,v 1.26 2006/11/28 22:58:04 mjt Exp $
.\" udns library manpage
.\"
.\" Copyright (C) 2005 Michael Tokarev <mjt at corpit.ru>
@@ -810,6 +810,48 @@
interest (if the \fIname\fR is absolute, that is, it ends up with a dot,
DNS_NOSRCH flag will be set automatically).
+.SS "NAPTR Queries"
+.PP
+.nf
+struct \fBdns_naptr\fR { /* single NAPTR record */
+ int \fBorder\fR; /* record order */
+ int \fBpreference\fR; /* preference of this record */
+ char *\fBflags\fR; /* application-specific flags */
+ char *\fBservices\fR; /* service parameters */
+ char *\fBregexp\fR; /* substitutional regular expression */
+ char *\fBreplacement\fR; /* replacement string */
+};
+struct \fBdns_rr_naptr\fR { /* NAPTR RRset */
+ char *\fBdnsnaptr_qname\fR; /* original query name */
+ char *\fBdnsnaptr_cname\fR; /* canonical name */
+ unsigned \fBdnsnaptr_ttl\fR; /* Time-To-Live (TTL) value */
+ int \fBdnsnaptr_nrr\fR; /* number of text records in the set */
+ struct dns_naptr \fBdnsnaptr_naptr\fR[]; /* array of NAPTR records */
+};
+typedef void
+ \fBdns_query_naptr_fn\fR(\fIctx\fR, struct dns_rr_naptr *\fIresult\fR, \fIdata\fR)
+dns_parse_fn \fBdns_parse_naptr\fB;
+struct dns_query *
+\fBdns_submit_naptr\fB(\fIctx\fR, const char *\fIname\fR, int \fIflags\fR,
+ dns_query_txt_fn *\fIcbck\fR, \fIdata\fR);
+struct dns_rr_naptr *
+\fBdns_resolve_naptr\fB(\fIctx\fR, const char *\fIname\fR, int \fIflags\fR);
+.fi
+.PP
+The \fBdns_rr_naptr\fR structure holds a result of an IN NAPTR (rfc3403) query.
+Callback routine for IN NAPTR queries expected to be of type
+\fBdns_query_naptr_fn\fR, expects pointer to \fBdns_rr_naptr\fR
+structure as query result instead of raw DNS packet.
+The \fBdns_parse_naptr\fR() is used to convert raw DNS reply packet into
+\fBdns_rr_naptr\fR structure (it is used
+internally and may be used directly too with generic query interface).
+Routines \fBdns_submit_naptr\fR() and \fBdns_resolve_naptr\fR() are used to
+perform IN NAPTR queries in a type-safe manner. The \fIname\fR parameter
+is the domain name in question, and \fIflags\fR is query flags bitmask,
+with one bit, DNS_NOSRCH, of practical interest (if the \fIname\fR is
+absolute, that is, it ends up with a dot, DNS_NOSRCH flag will be set
+automatically).
+
.SS "DNSBL Interface"
.PP
A DNS-based blocklists, or a DNSBLs, are in wide use nowadays, especially
Modified: udns/tags/upstream/0.0.9pre/udns.h
===================================================================
--- udns/branches/upstream/trunk/udns.h 2006-12-06 12:49:32 UTC (rev 2990)
+++ udns/tags/upstream/0.0.9pre/udns.h 2006-12-06 12:57:21 UTC (rev 2991)
@@ -1,4 +1,4 @@
-/* $Id: udns.h,v 1.37 2005/09/12 12:09:10 mjt Exp $
+/* $Id: udns.h,v 1.41 2006/11/29 01:20:30 mjt Exp $
header file for the UDNS library.
Copyright (C) 2005 Michael Tokarev <mjt at corpit.ru>
@@ -23,7 +23,7 @@
#ifndef UDNS_VERSION /* include guard */
-#define UDNS_VERSION "0.0.8"
+#define UDNS_VERSION "0.0.9pre"
#ifdef WIN32
# ifdef UDNS_DYNAMIC_LIBRARY
@@ -479,8 +479,7 @@
UDNS_API int
dns_cancel(struct dns_ctx *ctx, struct dns_query *q);
-/* immediately resolve a generic query, return the answer
- * and place completion status into *statusp */
+/* resolve a generic query, return the answer */
UDNS_API void *
dns_resolve_dn(struct dns_ctx *ctx,
dnscc_t *qdn, int qcls, int qtyp, int flags,
@@ -636,8 +635,34 @@
const char *name, const char *srv, const char *proto,
int flags);
+/* NAPTR (RFC3403) RR type */
+struct dns_naptr { /* single NAPTR RR */
+ int order; /* NAPTR order */
+ int preference; /* NAPTR preference */
+ char *flags; /* NAPTR flags */
+ char *service; /* NAPTR service */
+ char *regexp; /* NAPTR regexp */
+ char *replacement; /* NAPTR replacement */
+};
+struct dns_rr_naptr { /* the NAPTR RRset */
+ dns_rr_common(dnsnaptr);
+ struct dns_naptr *dnsnaptr_naptr; /* array of NAPTRes */
+};
+UDNS_API dns_parse_fn dns_parse_naptr; /* NAPTR RR parsing routine */
+typedef void /* NAPTR RR callback */
+dns_query_naptr_fn(struct dns_ctx *ctx,
+ struct dns_rr_naptr *result, void *data);
+/* submit NAPTR IN query */
UDNS_API struct dns_query *
+dns_submit_naptr(struct dns_ctx *ctx, const char *name, int flags,
+ dns_query_naptr_fn *cbck, void *data);
+/* resolve NAPTR IN query */
+UDNS_API struct dns_rr_naptr *
+dns_resolve_naptr(struct dns_ctx *ctx, const char *name, int flags);
+
+
+UDNS_API struct dns_query *
dns_submit_a4dnsbl(struct dns_ctx *ctx,
const struct in_addr *addr, const char *dnsbl,
dns_query_a4_fn *cbck, void *data);
@@ -693,11 +718,11 @@
UDNS_DATA_API extern const struct dns_nameval dns_rcodetab[];
UDNS_API int
dns_findname(const struct dns_nameval *nv, const char *name);
-#define dns_findclassname(class) dns_findname(dns_classtab, (class))
+#define dns_findclassname(cls) dns_findname(dns_classtab, (cls))
#define dns_findtypename(type) dns_findname(dns_typetab, (type))
#define dns_findrcodename(rcode) dns_findname(dns_rcodetab, (rcode))
-UDNS_API const char *dns_classname(enum dns_class class);
+UDNS_API const char *dns_classname(enum dns_class cls);
UDNS_API const char *dns_typename(enum dns_type type);
UDNS_API const char *dns_rcodename(enum dns_rcode rcode);
const char *_dns_format_code(char *buf, const char *prefix, int code);
Modified: udns/tags/upstream/0.0.9pre/udns_dn.c
===================================================================
--- udns/branches/upstream/trunk/udns_dn.c 2006-12-06 12:49:32 UTC (rev 2990)
+++ udns/tags/upstream/0.0.9pre/udns_dn.c 2006-12-06 12:57:21 UTC (rev 2991)
@@ -1,4 +1,4 @@
-/* $Id: udns_dn.c,v 1.6 2005/09/12 10:55:21 mjt Exp $
+/* $Id: udns_dn.c,v 1.7 2006/11/28 22:45:20 mjt Exp $
domain names manipulation routines
Copyright (C) 2005 Michael Tokarev <mjt at corpit.ru>
@@ -71,7 +71,7 @@
dnsc_t *const de /* end of dn: last byte that can be filled up */
= dn + (dnsiz >= DNS_MAXDN ? DNS_MAXDN : dnsiz) - 1;
dnscc_t *np = (dnscc_t *)name;
- dnscc_t *ne = np + (namelen ? namelen : strlen(np));
+ dnscc_t *ne = np + (namelen ? namelen : strlen((char*)np));
dnsc_t *llab; /* start of last label (llab[-1] will be length) */
unsigned c; /* next input character, or length of last label */
Modified: udns/tags/upstream/0.0.9pre/udns_resolver.c
===================================================================
--- udns/branches/upstream/trunk/udns_resolver.c 2006-12-06 12:49:32 UTC (rev 2990)
+++ udns/tags/upstream/0.0.9pre/udns_resolver.c 2006-12-06 12:57:21 UTC (rev 2991)
@@ -1,4 +1,4 @@
-/* $Id: udns_resolver.c,v 1.53 2005/09/12 10:23:08 mjt Exp $
+/* $Id: udns_resolver.c,v 1.57 2006/11/29 01:17:43 mjt Exp $
resolver stuff (main module)
Copyright (C) 2005 Michael Tokarev <mjt at corpit.ru>
@@ -24,6 +24,8 @@
#ifdef WIN32
# include <winsock2.h> /* includes <windows.h> */
# include <ws2tcpip.h> /* needed for struct in6_addr */
+# include <iphlpapi.h> /* for dns server addresses etc */
+# undef HAVE_POLL
#else
# include <sys/types.h>
# include <sys/socket.h>
@@ -255,7 +257,7 @@
if (!serv)
return (ctx->dnsc_nserv = 0);
if (ctx->dnsc_nserv >= DNS_MAXSERV)
- return errno = EOVERFLOW, -1;
+ return errno = ENFILE, -1;
sns = &ctx->dnsc_serv[ctx->dnsc_nserv];
memset(sns, 0, sizeof(*sns));
#if HAVE_INET6
@@ -301,7 +303,7 @@
if (!sa)
return (ctx->dnsc_nserv = 0);
if (ctx->dnsc_nserv >= DNS_MAXSERV)
- return errno = EOVERFLOW, -1;
+ return errno = ENFILE, -1;
#if HAVE_INET6
else if (sa->sa_family == AF_INET6)
ctx->dnsc_serv[ctx->dnsc_nserv].sin6 = *(struct sockaddr_in6*)sa;
@@ -380,7 +382,7 @@
if (!srch)
return (ctx->dnsc_nsrch = 0);
else if (ctx->dnsc_nsrch >= DNS_MAXSRCH)
- return errno = EOVERFLOW, -1;
+ return errno = ENFILE, -1;
else if (dns_sptodn(srch, ctx->dnsc_srch[ctx->dnsc_nsrch], DNS_MAXDN) <= 0)
return errno = EINVAL, -1;
else
@@ -461,17 +463,17 @@
int ret = -1;
h_iphlpapi = LoadLibrary("iphlpapi.dll");
- if (h_iphlpapi == HANDLE_ERROR)
+ if (!h_iphlpapi)
return -1;
pfnGetAdAddrs = (GetAdaptersAddressesFunc)
- GetProcAddress(iphlp, "GetAdaptersAddresses");
+ GetProcAddress(h_iphlpapi, "GetAdaptersAddresses");
if (!pfnGetAdAddrs) goto freelib;
ulOutBufLen = 0;
- dwRetVal = GetAdAddrs(AF_UNSPEC, 0, NULL, NULL, &ulOutBufLen);
+ dwRetVal = pfnGetAdAddrs(AF_UNSPEC, 0, NULL, NULL, &ulOutBufLen);
if (dwRetVal != ERROR_BUFFER_OVERFLOW) goto freelib;
pAddrBuf = malloc(ulOutBufLen);
if (!pAddrBuf) goto freelib;
- dwRetVal = GetAdAddrs(AF_UNSPEC, 0, NULL, pAddrBuf, &ulOutBufLen);
+ dwRetVal = pfnGetAdAddrs(AF_UNSPEC, 0, NULL, pAddrBuf, &ulOutBufLen);
if (dwRetVal != ERROR_SUCCESS) goto freemem;
for (pAddr = pAddrBuf;
pAddr && ctx->dnsc_nserv <= DNS_MAXSERV;
@@ -507,7 +509,7 @@
res = RegQueryValueEx(hk, "NameServer", NULL, &type, valBuf, &len);
if (res != ERROR_SUCCESS || !len || !valBuf[0]) {
len = sizeof(valBuf) - 1;
- res = RegQueryValueEx(hk, "DhcpNameServer", &type, valBuf, &len);
+ res = RegQueryValueEx(hk, "DhcpNameServer", NULL, &type, valBuf, &len);
}
RegCloseKey(hk);
if (res != ERROR_SUCCESS || !len || !valBuf[0])
@@ -751,7 +753,7 @@
void dns_close(struct dns_ctx *ctx) {
SETCTXINITED(ctx);
if (ctx->dnsc_udpsock < 0) return;
- close(ctx->dnsc_udpsock);
+ closesocket(ctx->dnsc_udpsock);
ctx->dnsc_udpsock = -1;
free(ctx->dnsc_pbuf);
ctx->dnsc_pbuf = NULL;
@@ -1039,7 +1041,7 @@
* remote errors should be ignored (for now anyway).
*/
#ifdef WIN32
- if (WSAGetLastError() != WSAEWOULDBLOCK)
+ if (WSAGetLastError() == WSAEWOULDBLOCK)
#else
if (errno == EAGAIN)
#endif
@@ -1250,9 +1252,6 @@
void *dns_resolve(struct dns_ctx *ctx, struct dns_query *q) {
time_t now;
-#ifdef WIN32
-# warning fixme: poll()/select() on WIN32 (WaitForMultipleObjects?)
-#endif
#ifdef HAVE_POLL
struct pollfd pfd;
#else
Added: udns/tags/upstream/0.0.9pre/udns_rr_naptr.c
===================================================================
--- udns/branches/upstream/trunk/udns_rr_naptr.c 2006-12-06 12:49:32 UTC (rev 2990)
+++ udns/tags/upstream/0.0.9pre/udns_rr_naptr.c 2006-12-06 12:57:21 UTC (rev 2991)
@@ -0,0 +1,128 @@
+/* $Id: udns_rr_naptr.c,v 1.1 2006/11/28 22:58:04 mjt Exp $
+ parse/query NAPTR IN records
+
+ Copyright (C) 2005 Michael Tokarev <mjt at corpit.ru>
+ Copyright (C) 2006 Mikael Magnusson <mikma at users.sourceforge.net>
+ This file is part of UDNS library, an async DNS stub resolver.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library, in file named COPYING.LGPL; if not,
+ write to the Free Software Foundation, Inc., 59 Temple Place,
+ Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "udns.h"
+
+/* Get a single string for NAPTR record, pretty much like a DN label.
+ * String length is in first byte in *cur, so it can't be >255.
+ */
+static int dns_getstr(dnscc_t **cur, dnscc_t *ep, char *buf)
+{
+ unsigned l;
+ dnscc_t *cp = *cur;
+
+ l = *cp++;
+ if (cp + l > ep)
+ return DNS_E_PROTOCOL;
+ if (buf) {
+ memcpy(buf, cp, l);
+ buf[l] = '\0';
+ }
+ cp += l;
+
+ *cur = cp;
+ return l + 1;
+}
+
+int
+dns_parse_naptr(dnscc_t *qdn, dnscc_t *pkt, dnscc_t *cur, dnscc_t *end,
+ void **result) {
+ struct dns_rr_naptr *ret;
+ struct dns_parse p;
+ struct dns_rr rr;
+ int r, l;
+ char *sp;
+ dnsc_t dn[DNS_MAXDN];
+
+ assert(dns_get16(cur+2) == DNS_C_IN && dns_get16(cur+0) == DNS_T_NAPTR);
+
+ /* first, validate the answer and count size of the result */
+ l = 0;
+ dns_initparse(&p, qdn, pkt, cur, end);
+ while((r = dns_nextrr(&p, &rr)) > 0) {
+ int i;
+ dnscc_t *ep = rr.dnsrr_dend;
+
+ /* first 4 bytes: order & preference */
+ cur = rr.dnsrr_dptr + 4;
+
+ /* flags, services and regexp */
+ for (i = 0; i < 3; i++) {
+ r = dns_getstr(&cur, ep, NULL);
+ if (r < 0)
+ return r;
+ l += r;
+ }
+ /* replacement */
+ r = dns_getdn(pkt, &cur, end, dn, sizeof(dn));
+ if (r <= 0 || cur != rr.dnsrr_dend)
+ return DNS_E_PROTOCOL;
+ l += dns_dntop_size(dn);
+ }
+ if (r < 0)
+ return DNS_E_PROTOCOL;
+ if (!p.dnsp_nrr)
+ return DNS_E_NODATA;
+
+ /* next, allocate and set up result */
+ l += dns_stdrr_size(&p);
+ ret = malloc(sizeof(*ret) + sizeof(struct dns_naptr) * p.dnsp_nrr + l);
+ if (!ret)
+ return DNS_E_NOMEM;
+ ret->dnsnaptr_nrr = p.dnsp_nrr;
+ ret->dnsnaptr_naptr = (struct dns_naptr *)(ret+1);
+
+ /* and 3rd, fill in result, finally */
+ sp = (char*)(&ret->dnsnaptr_naptr[p.dnsp_nrr]);
+ for (dns_rewind(&p, qdn), r = 0; dns_nextrr(&p, &rr); ++r) {
+ cur = rr.dnsrr_dptr;
+ ret->dnsnaptr_naptr[r].order = dns_get16(cur); cur += 2;
+ ret->dnsnaptr_naptr[r].preference = dns_get16(cur); cur += 2;
+ sp += dns_getstr(&cur, end, (ret->dnsnaptr_naptr[r].flags = sp));
+ sp += dns_getstr(&cur, end, (ret->dnsnaptr_naptr[r].service = sp));
+ sp += dns_getstr(&cur, end, (ret->dnsnaptr_naptr[r].regexp = sp));
+ dns_getdn(pkt, &cur, end, dn, sizeof(dn));
+ sp += dns_dntop(dn, (ret->dnsnaptr_naptr[r].replacement = sp), DNS_MAXNAME);
+ }
+ dns_stdrr_finish((struct dns_rr_null *)ret, sp, &p);
+ *result = ret;
+ return 0;
+}
+
+struct dns_query *
+dns_submit_naptr(struct dns_ctx *ctx, const char *name, int flags,
+ dns_query_naptr_fn *cbck, void *data) {
+ return
+ dns_submit_p(ctx, name, DNS_C_IN, DNS_T_NAPTR, flags,
+ dns_parse_naptr, (dns_query_fn *)cbck, data);
+}
+
+struct dns_rr_naptr *
+dns_resolve_naptr(struct dns_ctx *ctx, const char *name, int flags) {
+ return (struct dns_rr_naptr *)
+ dns_resolve_p(ctx, name, DNS_C_IN, DNS_T_NAPTR, flags, dns_parse_naptr);
+}
Property changes on: udns/tags/upstream/0.0.9pre/udns_rr_naptr.c
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Name: svn:eol-style
+ native
Modified: udns/tags/upstream/0.0.9pre/udns_rr_txt.c
===================================================================
--- udns/branches/upstream/trunk/udns_rr_txt.c 2006-12-06 12:49:32 UTC (rev 2990)
+++ udns/tags/upstream/0.0.9pre/udns_rr_txt.c 2006-12-06 12:57:21 UTC (rev 2991)
@@ -1,4 +1,4 @@
-/* $Id: udns_rr_txt.c,v 1.14 2005/04/20 06:44:34 mjt Exp $
+/* $Id: udns_rr_txt.c,v 1.15 2006/11/28 22:45:20 mjt Exp $
parse/query TXT records
Copyright (C) 2005 Michael Tokarev <mjt at corpit.ru>
@@ -78,7 +78,7 @@
ret->dnstxt_txt[r].len = sp - ret->dnstxt_txt[r].txt;
*sp++ = '\0';
}
- dns_stdrr_finish((struct dns_rr_null *)ret, sp, &p);
+ dns_stdrr_finish((struct dns_rr_null *)ret, (char*)sp, &p);
*result = ret;
return 0;
}
More information about the Minisip-devel
mailing list