[Zrouter-src] ZRouter.org: push to ZRouter contrib/spcdns/LICENSE contrib/spcd...
zrouter-src at zrouter.org
zrouter-src at zrouter.org
Wed Sep 19 12:22:03 UTC 2012
details: http://zrouter.org/hg/zrouter//rev/fee6b517c6d4
changeset: 426:fee6b517c6d4
user: Aleksandr Rybalko <ray at ddteam.net>
date: Wed Sep 19 15:25:04 2012 +0300
description:
Add spcdns, we can use it to get smallest dig like tool.
And for correct link test.
diffstat:
contrib/spcdns/LICENSE | 165 +++
contrib/spcdns/Makefile | 128 +++
contrib/spcdns/README | 156 +++
contrib/spcdns/lua/dns.lua | 54 +
contrib/spcdns/lua/mx.lua | 102 ++
contrib/spcdns/lua/test.lua | 213 +++++
contrib/spcdns/src/codec.c | 1695 ++++++++++++++++++++++++++++++++++++++++
contrib/spcdns/src/dns.h | 990 +++++++++++++++++++++++
contrib/spcdns/src/luadns.c | 768 ++++++++++++++++++
contrib/spcdns/src/mappings.c | 373 ++++++++
contrib/spcdns/src/mappings.h | 55 +
contrib/spcdns/src/netsimple.c | 156 +++
contrib/spcdns/src/netsimple.h | 75 +
contrib/spcdns/src/test.c | 563 +++++++++++++
14 files changed, 5493 insertions(+), 0 deletions(-)
diffs (5549 lines):
diff -r 3bd5c2e9e8ac -r fee6b517c6d4 contrib/spcdns/LICENSE
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/spcdns/LICENSE Wed Sep 19 15:25:04 2012 +0300
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff -r 3bd5c2e9e8ac -r fee6b517c6d4 contrib/spcdns/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/spcdns/Makefile Wed Sep 19 15:25:04 2012 +0300
@@ -0,0 +1,128 @@
+
+#######################################################################
+#
+# Copyright 2010 by Sean Conner. All Rights Reserved.
+#
+# 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 3 of the License, or (at your
+# option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+# License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, see <http://www.gnu.org/licenses/>.
+#
+######################################################################
+
+#================================================
+# Linux
+#================================================
+
+CC = gcc -g -std=c99
+CFLAGS = -Wall -Wextra -pedantic
+#CFLAGS = -Os -fomit-frame-pointer -DNDEBUG
+PIC = -fpic
+LFLAGS = -lm
+LUA = /usr/local/lib/lua/5.1
+AR = ar cr
+RANLIB = ranlib
+
+#=================================================
+# Solaris
+#=================================================
+
+#CC = cc -g -xc99
+#CFLAGS =
+#PIC = -fpic
+#LFLAGS = -lm -lnsl -lsocket
+#LUA = /usr/local/lib/lua/5.1
+#AR = ar cr
+#RANLIB = ranlib
+
+#=================================================
+
+dotest : built/dotest
+
+lua : built/dns.so
+
+lib : built/libspcdns.a
+
+so : built/libspcdns.so
+
+all : built/dotest built/dns.so built/libspcdns.a built/libspcdns.so
+
+#==================================================
+
+built/libspcdns.a : built/codec.o built/mappings.o
+ $(AR) $@ built/codec.o built/mappings.o
+ $(RANLIB) $@
+
+built/libspcdns.so : built/codec.pic.o built/mappings.pic.o
+ $(CC) -shared -o $@ built/codec.pic.o built/mappings.pic.o
+
+built/codec.o : src/codec.c src/dns.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+built/codec.pic.o : src/codec.c src/dns.h
+ $(CC) $(CFLAGS) $(PIC) -c -o $@ $<
+
+built/mappings.o : src/mappings.c src/mappings.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+built/mappings.pic.o : src/mappings.c src/mappings.h
+ $(CC) $(CFLAGS) $(PIC) -c -o $@ $<
+
+built/netsimple.o : src/netsimple.c src/netsimple.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+built/netsimple.pic.o : src/netsimple.c src/netsimple.h
+ $(CC) $(CFLAGS) $(PIC) -c -o $@ $<
+
+#==============================================================
+
+
+built/dotest : built/test.o \
+ built/codec.o \
+ built/mappings.o \
+ built/netsimple.o
+ $(CC) -o $@ built/test.o \
+ built/codec.o \
+ built/mappings.o \
+ built/netsimple.o \
+ $(LFLAGS)
+
+built/test.o : src/test.c src/dns.h src/mappings.h src/netsimple.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+#=============================================================
+
+built/dns.so : built/luadns.o \
+ built/codec.pic.o \
+ built/mappings.pic.o \
+ built/netsimple.pic.o
+ $(CC) -o $@ -shared \
+ built/luadns.o \
+ built/codec.pic.o \
+ built/mappings.pic.o \
+ built/netsimple.pic.o
+
+
+built/luadns.o : src/luadns.c src/dns.h src/mappings.h
+ $(CC) $(CFLAGS) $(PIC) -c -o $@ $<
+
+#===========================================================
+
+install-lua: built/dns.so
+ install -d $(LUA)/org/conman
+ install built/dns.so $(LUA)/org/conman
+
+clean:
+ /bin/rm -rf built/*
+ /bin/rm -rf *~ src/*~ lua/*~
+
+tarball:
+ (cd .. ; tar czvf /tmp/spcdns.tar.gz -X spcdns/.exclude spcdns/ )
diff -r 3bd5c2e9e8ac -r fee6b517c6d4 contrib/spcdns/README
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/spcdns/README Wed Sep 19 15:25:04 2012 +0300
@@ -0,0 +1,156 @@
+
+SPCDNS: The sane DNS encoding/decoding library
+
+SPCDNS implements a simple yet sane API to encode DNS queries and to decode
+DNS replies. The library (v1.0) currently supports the decoding of 30 DNS
+resource records, which is more than just about all other DNS resolving
+libraries I've seen (c-ares, udns, adns, libdns and djbdns [1]).
+
+SPCDNS is *NOT* a general purpose DNS resolving library (although code is
+provided to make DNS queries, it is simple and fairly stupid). This code
+exists to provide a simple method of encoding and decoding the DNS protocol
+and thus the network side of things is a bit lacking I'll admit. But that
+is beyond what I wanted for this project anyway.
+
+In the "src/" directory you'll find the following:
+
+ dns.h
+
+ Defines the various DNS RR types, a structure for an
+ in-memory representation of each RR type (which is what
+ you'll get back when you call the decoding routine), and the
+ definitions for two functions, dns_encode() and dns_decode()
+ which pretty much do what they say.
+
+ codec.c
+
+ The actual implementations of dns_encode() and dns_decode().
+ This is the only file that's needed to encode and decode the
+ raw DNS protocol. The routines are thread safe, do *not*
+ allocate memory (see below for more details) and do not use
+ signals. It also does not use code from any other file in
+ this package.
+
+ mappings.h
+ mappings.c
+
+ These files provide definitions and implementation of a few
+ helpful routines that return string representations of the
+ DNS RR types, classes, opcodes and errors. Again, thread
+ safe and no memory allocations made.
+
+ netsimple.h
+ netsimple.c
+
+ These files provide definitions and implementations for
+ making simple DNS queries to a given server. This code is
+ *simple* and *dumb*, it may be good for light usage but was
+ written to get actual DNS packets from a DNS server for
+ testing. This uses UDP and is thus limited to a query of
+ 512 bytes or less.
+
+ luadns.c
+
+ Lua [2] bindings for this library. It exports the routines
+ found in codec.c, mappings.c and netsimple.c. Not all the
+ DNS RR types decoded are supported as of yet, but the major
+ ones commonly used are supported.
+
+ test.c
+
+ An example program showing how to use the API to construct
+ and send a query, and to decode the response.
+
+You'll probably want to check the Makefile to make sure the right compiler
+and locations are set. Or not. You don't *HAVE* to use the included
+Makefile. It's really just a set of suggestions anyway.
+
+A NOTE ABOUT MEMORY ALLOCATIONS
+
+The dns_encode() and dns_decode() functions do no memory allocation; they
+use what you give them. In the case of dns_decode(), the block of memory
+passed in must be big enough to handle not only the dns_query_t structure,
+but multiple dns_answer_t structures and text strings representing domain
+names and the occasional string or two (say, for TXT or NAPTR records). In
+testing, I've found that 4K for decoding appears to be enough memory to
+handle DNS requests made via UDP (although the test.c program uses an 8K
+buffer).
+
+This block of memory should be properly aligned and to help make that easier
+I've defined two data types that should allow proper alignment, along with
+some useful constants to declare buffers of proper alignment and size.
+
+ dns_packet_t reply [DNS_BUFFER_UDP];
+ dns_decoded_t decoded[DNS_DECODEBUF_4K];
+ dns_query_t *result;
+ dns_rcode rc;
+ size_t replysize;
+ size_t decodesize;
+
+ /* assume reply contains a DNS packet, and replysize is set */
+
+ decodesize = sizeof(decoded);
+ rc = dns_decode(decoded,&decodesize,reply,replysize);
+
+ if (rc != RCODE_OKAY)
+ {
+ /* handle error */
+ }
+
+ result = (dns_query_t *)decoded;
+
+ /* go with processing the result */
+
+Do *NOT* assume that DNS_DECODEBUF_4K is equal to 4096---it's not. It
+*DOES*, however, result in at least a 4K block of memory made up of
+DNS_DECODEBUF_4K worth of dns_decoded_t types. By the same token, do *NOT*
+assume that DNS_BUFFER_UDP is 512, but it too, does result in a buffer of at
+least 512 bytes made up of DNS_BUFFER_UDP dns_packet_t types.
+
+And while passing in a char * declared buffer to dns_decode() may appear to
+work, it only works on *YOUR* system; it may not work on other systems.
+
+A NOTE ABOUT DOMAIN NAMES
+
+The dns_encode() function assumes the domain passed is a fully qualified
+domain name. If you see an RCODE_NAME_ERROR when calling this function, you
+are probably not passing in a FQDN (if you are and are still getting that
+error, it's most likely a domain name segment exceeding the 63 character DNS
+limit).
+
+SOME NOTES ABOUT THE LUA BINDINGS
+
+The Lua bindings are loaded into a Lua script with the following:
+
+ require "org.conman.dns"
+
+This loads the bindings into a global Lua table called "org.conman.dns" to
+avoid name conflicts with other Lua DNS bindings and/or libraries. Doing a
+"make install-lua" will install this file under:
+
+ /usr/local/lib/lua/5.1/org/conman/
+
+(assuming you didn't change the LUA setting in the Makefile)
+
+and thus place it under the appropriate namespace so Lua can find it.
+
+The file "lua/test.lua" shows the best use of the Lua bindings (and is close
+enough to what "src/test.c" does). Better network handling could be done
+using LuaSocket, but for that, you are on your own.
+
+A FINAL NOTE
+
+If you have any problems, questions or enhancements, please send them my
+way, to sean at conman.org.
+
+Thank you.
+
+[1] http://c-ares.haxx.se/
+ http://www.corpit.ru/mjt/udns.html
+ http://www.chiark.greenend.org.uk/~ian/adns/
+ http://www.25thandclement.com/~william/projects/dns.c.html
+ http://cr.yp.to/djbdns.html
+
+[2] http://www.lua.org/
+
+[3] http://w3.impa.br/~diego/software/luasocket/
diff -r 3bd5c2e9e8ac -r fee6b517c6d4 contrib/spcdns/lua/dns.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/spcdns/lua/dns.lua Wed Sep 19 15:25:04 2012 +0300
@@ -0,0 +1,54 @@
+#! /usr/bin/env lua
+-- *************************************************************************
+--
+-- Copyright 2010 by Sean Conner. All Rights Reserved.
+--
+-- 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 3 of the License, or (at your
+-- option) any later version.
+--
+-- This library is distributed in the hope that it will be useful, but
+-- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+-- License for more details.
+--
+-- You should have received a copy of the GNU Lesser General Public License
+-- along with this library; if not, see <http://www.gnu.org/licenses/>.
+--
+-- **************************************************************************
+
+dns = require "org.conman.dns"
+
+e = dns.encode {
+ id = 1234,
+ query = true,
+ rd = true,
+ opcode = 'query',
+ question = {
+ name = 'yahoo.com.',
+ type = 'mx',
+ class = 'in'
+ }
+}
+
+r,err = dns.query('127.0.0.1',e)
+
+if r == nil then
+ print("error:",err)
+ os.exit(1)
+end
+
+d = dns.decode(r)
+
+for i = 1 , #d.answers do
+ print(string.format("%s %d %s %s %d %s",
+ d.answers[i].name,
+ d.answers[i].ttl,
+ d.answers[i].class,
+ d.answers[i].type,
+ d.answers[i].preference,
+ d.answers[i].exchange
+ ))
+end
+
diff -r 3bd5c2e9e8ac -r fee6b517c6d4 contrib/spcdns/lua/mx.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/spcdns/lua/mx.lua Wed Sep 19 15:25:04 2012 +0300
@@ -0,0 +1,102 @@
+#!/usr/bin/env lua
+-- *************************************************************************
+--
+-- Copyright 2010 by Sean Conner. All Rights Reserved.
+--
+-- 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 3 of the License, or (at your
+-- option) any later version.
+--
+-- This library is distributed in the hope that it will be useful, but
+-- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+-- License for more details.
+--
+-- You should have received a copy of the GNU Lesser General Public License
+-- along with this library; if not, see <http://www.gnu.org/licenses/>.
+--
+-- **************************************************************************
+
+require "org.conman.dns"
+
+local SERVER = "127.0.0.1"
+local dns = org.conman.dns
+
+-- **************************************************************
+
+local function query(host,type)
+ local e = dns.encode {
+ id = math.random(),
+ query = true,
+ rd = true,
+ opcode = 'query',
+ question = {
+ name = host,
+ type = type,
+ class = 'in'
+ }
+ }
+
+ local r,err = dns.query(SERVER,e)
+
+ if r == nil then
+ print("error:",err)
+ return nil
+ end
+
+ return dns.decode(r)
+end
+
+-- ****************************************************************
+
+local function query_a(host)
+ local a,err = query(host,'a')
+
+ if a == nil then
+ print("error:",err)
+ return nil
+ end
+
+ return a.answers[1]
+end
+
+-- ****************************************************************
+
+local function query_mx(host)
+ local mx,err = query(host,'mx')
+
+ if mx == nil then
+ print("error:",err)
+ return nil
+ end
+
+ table.sort(mx.answers,function(a,b) return a.preference < b.preference end)
+
+ for i = 1 , #mx.answers do
+ mx.answers[i].ADDRESS = mx.additional[mx.answers[i].exchange]
+ if mx.answers[i].ADDRESS == nil then
+ mx.answers[i].ADDRESS = query_a(mx.answers[i].exchange)
+ end
+ end
+
+ return mx.answers
+end
+
+-- **************************************************************
+
+if #arg == 0 then
+ io.stderr:write(string.format("usage: %s domain\n",arg[0]))
+ os.exit(1)
+end
+
+local results = query_mx(arg[1])
+
+for i = 1 , #results do
+ local mx,ip
+
+ mx = results[i].exchange
+ ip = results[i].ADDRESS.address or "(none)"
+
+ print(mx,ip)
+end
diff -r 3bd5c2e9e8ac -r fee6b517c6d4 contrib/spcdns/lua/test.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/spcdns/lua/test.lua Wed Sep 19 15:25:04 2012 +0300
@@ -0,0 +1,213 @@
+#!/usr/bin/env lua
+-- *************************************************************************
+--
+-- Copyright 2010 by Sean Conner. All Rights Reserved.
+--
+-- 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 3 of the License, or (at your
+-- option) any later version.
+--
+-- This library is distributed in the hope that it will be useful, but
+-- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+-- License for more details.
+--
+-- You should have received a copy of the GNU Lesser General Public License
+-- along with this library; if not, see <http://www.gnu.org/licenses/>.
+--
+-- **************************************************************************
+
+require "org.conman.dns"
+
+local SERVER = "127.0.0.1"
+local dns = org.conman.dns
+
+-- **************************************************************
+
+local function query(host,type)
+ local e
+ local r
+ local err
+
+ e,err = dns.encode {
+ id = math.random(),
+ query = true,
+ rd = true,
+ opcode = 'query',
+ question = {
+ name = host,
+ type = type,
+ class = 'in'
+ }
+ }
+
+ if e == nil then
+ return e,err
+ end
+
+ r,err = dns.query(SERVER,e)
+
+ if r == nil then
+ return r,err
+ end
+
+ return dns.decode(r)
+end
+
+-- ****************************************************************
+
+local function print_txt(rec)
+ if type(rec.txt) == 'string' then
+ return rec.txt
+ elseif type(rec.txt) == 'table' then
+ local s = "("
+ for i = 1 , #rec.txt do
+ s = s .. string.format("\n\t\t\t%q",rec.txt[i])
+ end
+ s = s .. "\n\t\t)"
+ return s
+ else
+ return ""
+ end
+end
+
+local callbacks =
+{
+ NS = function(rec) return rec.nsdname end,
+ A = function(rec) return rec.address end,
+ AAAA = function(rec) return rec.address end,
+ CNAME = function(rec) return rec.cname end,
+ MX = function(rec) return string.format("%5d %s",rec.preference,rec.exchange) end,
+ PTR = function(rec) return rec.ptr end,
+ HINFO = function(rec) return string.format("%q %q",rec.cpu,rec.os) end,
+ SPF = print_txt,
+ TXT = print_txt,
+ SOA = function(rec) return string.format([[
+%s %s (
+ %10d ; Serial
+ %10d ; Refresh
+ %10d ; Retry
+ %10d ; Expire
+ %10d ) ; Miminum
+]],
+ rec.mname,
+ rec.rname,
+ rec.serial,
+ rec.refresh,
+ rec.retry,
+ rec.expire,
+ rec.minimum ) end,
+ NAPTR = function(rec) return string.format([[
+%5d %5d (
+ %q
+ %q
+ %q
+ %s )
+]],
+ rec.order,
+ rec.preference,
+ rec.flags,
+ rec.services,
+ rec.regexp,
+ rec.replacement) end,
+ SRV = function(rec) return string.format(
+ "%5d %5d %5d %s",
+ rec.priority,
+ rec.weight,
+ rec.port,
+ rec.target) end,
+ LOC = function(rec) return string.format([[
+(
+ %3d %2d %2d %s ; Latitude
+ %3d %2d %2d %s ; Longitude
+ %11d ; Altitude
+ %11d ; Size
+ %11d ; Horizontal Precision
+ %11d ; Vertical Precision
+ )
+]],
+ rec.latitude.deg,
+ rec.latitude.min,
+ rec.latitude.sec,
+ rec.latitude.hemisphere,
+ rec.longitude.deg,
+ rec.longitude.min,
+ rec.longitude.sec,
+ rec.longitude.hemisphere,
+ rec.altitude,
+ rec.size,
+ rec.horiz_pre,
+ rec.vert_pre ) end
+}
+
+local function print_answers(tag,recs)
+ io.stdout:write(string.format("\n;;; %s\n\n",tag))
+
+ for i = 1 , #recs do
+ s = string.format("%-16s\t%d\t%s\t%s\t",
+ recs[i].name,
+ recs[i].ttl,
+ recs[i].class,
+ recs[i].type
+ )
+ s = s .. callbacks[recs[i].type](recs[i]) .. "\n"
+ io.stdout:write(s)
+ end
+end
+
+-- **********************************************************************
+
+
+if #arg == 0 then
+ io.stderr:write(string.format("usage: %s type domain\n",arg[0]))
+ os.exit(1)
+end
+
+local results,err
+
+results,err = query(arg[2],arg[1])
+
+if results == nil then
+ io.stderr:write(string.format(
+ "error: query(%s,%s) = %s",
+ arg[2],
+ arg[1],
+ err
+ ))
+ os.exit(1)
+end
+
+io.stdout:write(string.format([[
+; Questions = 1
+; Answers = %d
+; Name Servers = %d
+; Additional Records = %d
+; Authoritative Result = %s
+; Truncated Result = %s
+; Recursion Desired = %s
+; Recursion Available = %s
+; Result = %s
+
+;;; QUESTIONS
+
+; %s %s %s
+]],
+ #results.answers,
+ #results.nameservers,
+ #results.additional,
+ tostring(results.aa),
+ tostring(results.tc),
+ tostring(results.rd),
+ tostring(results.ra),
+ dns.strerror(results.rcode),
+ results.question.name,
+ results.question.class,
+ results.question.type
+))
+
+print_answers("ANSWERS" , results.answers)
+print_answers("NAMESERVERS" , results.nameservers)
+print_answers("ADDITIONAL" , results.additional)
+
+os.exit(0)
diff -r 3bd5c2e9e8ac -r fee6b517c6d4 contrib/spcdns/src/codec.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/spcdns/src/codec.c Wed Sep 19 15:25:04 2012 +0300
@@ -0,0 +1,1695 @@
+/*************************************************************************
+*
+* Copyright 2010 by Sean Conner. All Rights Reserved.
+*
+* 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 3 of the License, or (at your
+* option) any later version.
+*
+* This library is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+* License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with this library; if not, see <http://www.gnu.org/licenses/>.
+*
+**************************************************************************/
+
+/**********************************************************************
+*
+* Implements the code to encode a DNS query (*NOTE* only queries at this
+* time) and to decode responses from a DNS server. This exports two
+* functions:
+*
+* dns_encode()
+*
+* This function takes a filled in dns_query_t structure (assumed to be
+* filled out correctly and creates the wire representation of that
+* query into a buffer supplied to the routine.
+*
+* THIS ROUTINE DOES NOT ALLOCATE MEMORY, NOR DOES IT USE GLOBAL
+* VARAIBLES. IT IS THEREFORE THREAD SAFE.
+*
+* See test.c for an example of calling this routine.
+*
+* dns_decode()
+*
+* This function takes the wire representation of a response, decodes
+* and returns a dns_query_t filled out with the various records. You
+* supply a block of memory sufficient enough to store the dns_query_t
+* and any various strings/structures used in the dns_query_t (I've
+* found 8K to be more than enough for decoding a UDP response but
+* that's a very conservative value; 4K may be good enough).
+*
+* THIS ROUTINE DOES NOT ALLOCATE MEMORY, NOR DOES IT USE GLOBAL
+* VARIABLES. IT IS THEREFORE THREAD SAFE.
+*
+* See test.c for an example of calling this routine.
+*
+* This code is written using C99.
+*
+* The code in here requires no other code from this project.
+*
+****************************************************************************/
+
+#define _GNU_SOURCE
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <math.h>
+#include <assert.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include "dns.h"
+
+/*----------------------------------------------------------------------------
+; The folowing are used for memory allocation. dns_decoded_t should be fine
+; for alignment size, as it's good enough for alignment. If some odd-ball
+; system comes up that requires more strict alignment, then I'll change this
+; to something like a long double or something silly like that.
+;
+; see the comment align_memory() for more details
+;-----------------------------------------------------------------------------*/
+
+#define MEM_ALIGN sizeof(dns_decoded_t)
+#define MEM_MASK ~(sizeof(dns_decoded_t) - 1uL)
+
+/************************************************************************/
+
+typedef struct block
+{
+ size_t size;
+ uint8_t *ptr;
+} block_t;
+
+struct idns_header
+{
+ uint16_t id;
+ uint8_t opcode;
+ uint8_t rcode;
+ uint16_t qdcount;
+ uint16_t ancount;
+ uint16_t nscount;
+ uint16_t arcount;
+} __attribute__ ((packed));
+
+typedef struct idns_context
+{
+ block_t packet;
+ block_t parse;
+ block_t dest; /* see comments in align_memory() */
+ dns_query_t *response;
+ bool edns;
+} idns_context;
+
+/***********************************************************************/
+
+static dns_rcode_t dns_encode_domain (block_t *const restrict,const dns_question_t *const restrict) __attribute__ ((nothrow,nonnull));
+static inline dns_rcode_t encode_edns0rr_nsid (block_t *const restrict,const edns0_opt_t *const restrict) __attribute__ ((nothrow,nonnull));
+static inline dns_rcode_t encode_edns0rr_raw (block_t *const restrict,const edns0_opt_t *const restrict) __attribute__ ((nothrow,nonnull));
+static inline dns_rcode_t encode_rr_opt (block_t *const restrict,const dns_query_t *const restrict,const dns_edns0opt_t *const restrict) __attribute__ ((nothrow,nonnull));
+
+static bool align_memory (block_t *const) __attribute__ ((nothrow,nonnull, warn_unused_result));
+static void *alloc_struct (block_t *const,const size_t) __attribute__ ((nothrow,nonnull(1),warn_unused_result,malloc));
+
+static inline void write_uint16 (block_t *const,uint16_t) __attribute__ ((nothrow,nonnull(1)));
+static inline void write_uint32 (block_t *const,uint32_t) __attribute__ ((nothrow,nonnull(1)));
+static inline uint16_t read_uint16 (block_t *const) __attribute__ ((nothrow,nonnull));
+static inline uint32_t read_uint32 (block_t *const) __attribute__ ((nothrow,nonnull));
+static dns_rcode_t read_raw (idns_context *const restrict,uint8_t **restrict,const size_t) __attribute__ ((nothrow,nonnull(1,2)));
+static dns_rcode_t read_string (idns_context *const restrict,const char **restrict) __attribute__ ((nothrow,nonnull(1,2)));
+static dns_rcode_t read_domain (idns_context *const restrict,const char **restrict) __attribute__ ((nothrow,nonnull));
+
+static inline dns_rcode_t decode_edns0rr_nsid (idns_context *const restrict,edns0_opt_t *const restrict) __attribute__ ((nothrow,nonnull));
+static inline dns_rcode_t decode_edns0rr_raw (idns_context *const restrict,edns0_opt_t *const restrict) __attribute__ ((nothrow,nonnull));
+
+static dns_rcode_t decode_question(idns_context *const restrict,dns_question_t *const restrict) __attribute__ ((nothrow,nonnull));
+static inline dns_rcode_t decode_rr_soa (idns_context *const restrict,dns_soa_t *const restrict,const size_t) __attribute__ ((nothrow,nonnull(1,2)));
+static inline dns_rcode_t decode_rr_a (idns_context *const restrict,dns_a_t *const restrict,const size_t) __attribute__ ((nothrow,nonnull(1,2)));
+static inline dns_rcode_t decode_rr_wks (idns_context *const restrict,dns_wks_t *const restrict,const size_t) __attribute__ ((nothrow,nonnull(1,2)));
+static inline dns_rcode_t decode_rr_mx (idns_context *const restrict,dns_mx_t *const restrict,const size_t) __attribute__ ((nothrow,nonnull(1,2)));
+static inline dns_rcode_t decode_rr_txt (idns_context *const restrict,dns_txt_t *const restrict,const size_t) __attribute__ ((nothrow,nonnull(1,2)));
+static inline dns_rcode_t decode_rr_hinfo(idns_context *const restrict,dns_hinfo_t *const restrict) __attribute__ ((nothrow,nonnull(1,2)));
+static inline dns_rcode_t decode_rr_naptr(idns_context *const restrict,dns_naptr_t *const restrict,const size_t) __attribute__ ((nothrow,nonnull(1,2)));
+static inline dns_rcode_t decode_rr_aaaa (idns_context *const restrict,dns_aaaa_t *const restrict,const size_t) __attribute__ ((nothrow,nonnull(1,2)));
+static inline dns_rcode_t decode_rr_srv (idns_context *const restrict,dns_srv_t *const restrict,const size_t) __attribute__ ((nothrow,nonnull(1,2)));
+static inline dns_rcode_t decode_rr_sig (idns_context *const restrict,dns_sig_t *const restrict,const size_t) __attribute__ ((nothrow,nonnull(1,2)));
+static inline dns_rcode_t decode_rr_minfo(idns_context *const restrict,dns_minfo_t *const restrict) __attribute__ ((nothrow,nonnull(1,2)));
+static inline dns_rcode_t decode_rr_gpos (idns_context *const restrict,dns_gpos_t *const restrict) __attribute__ ((nothrow,nonnull(1,2)));
+static inline dns_rcode_t decode_rr_loc (idns_context *const restrict,dns_loc_t *const restrict,const size_t) __attribute__ ((nothrow,nonnull(1,2)));
+static inline dns_rcode_t decode_rr_opt (idns_context *const restirct,dns_edns0opt_t *const restrict,const size_t) __attribute__ ((nothrow,nonnull(1,2)));
+static dns_rcode_t decode_answer (idns_context *const restrict,dns_answer_t *const restirct) __attribute__ ((nothrow,nonnull(1,2)));
+
+/***********************************************************************/
+
+#ifndef NDEBUG
+ static int query_okay (const dns_query_t *const) __attribute__ ((unused));
+ static int pblock_okay (const block_t *const) __attribute__ ((unused));
+ static int block_okay (const block_t) __attribute__ ((unused));
+ static int context_okay(const idns_context *const) __attribute__ ((unused));
+
+ static int query_okay(const dns_query_t *const query)
+ {
+ assert(query != NULL);
+ assert(query->id >= 0);
+ assert(query->id <= UINT16_MAX);
+ assert(query->opcode <= 2);
+ assert(query->rcode <= 5);
+ assert(query->qdcount <= UINT16_MAX);
+ assert(query->ancount <= UINT16_MAX);
+ assert(query->nscount <= UINT16_MAX);
+ assert(query->arcount <= UINT16_MAX);
+
+ if (query->query)
+ {
+ assert((query->opcode == OP_QUERY) || (query->opcode == OP_IQUERY));
+ assert(!query->aa);
+ assert(!query->tc);
+ assert(!query->ra);
+ assert(query->rcode == RCODE_OKAY);
+ }
+ return 1;
+ }
+
+ static int pblock_okay(const block_t *const block)
+ {
+ assert(block != NULL);
+ assert(block->ptr != NULL);
+ assert(block->size > 0);
+ return 1;
+ }
+
+ static int block_okay(const block_t block)
+ {
+ assert(block.ptr != NULL);
+ assert(block.size > 0);
+ return 1;
+ }
+
+ static int context_okay(const idns_context *const data)
+ {
+ assert(data != NULL);
+ assert(data->response != NULL);
+ assert(block_okay(data->packet));
+ assert(block_okay(data->parse));
+ assert(block_okay(data->dest));
+ return 1;
+ }
+#endif
+
+/*******************************************************************/
+
+dns_rcode_t dns_encode(
+ dns_packet_t *const restrict dest,
+ size_t *const restrict plen,
+ const dns_query_t *const restrict query
+)
+{
+ struct idns_header *header;
+ uint8_t *buffer;
+ block_t data;
+ dns_rcode_t rc;
+
+ assert(dest != NULL);
+ assert(plen != NULL);
+ assert(*plen >= sizeof(struct idns_header));
+ assert(query_okay(query));
+
+ memset(dest,0,*plen);
+
+ buffer = (uint8_t *)dest;
+ header = (struct idns_header *)buffer;
+
+ header->id = htons(query->id);
+ header->opcode = (query->opcode & 0x0F) << 3;
+ header->rcode = (query->rcode & 0x0F);
+ header->qdcount = htons(query->qdcount);
+ header->ancount = htons(query->ancount);
+ header->nscount = htons(query->nscount);
+ header->arcount = htons(query->arcount);
+
+ /*-----------------------------------------------------------------------
+ ; I'm not bothering with symbolic constants for the flags; they're only
+ ; used in two places in the code (the other being dns_encode()) and
+ ; they're not going to change. It's also obvious from the context what
+ ; they're refering to.
+ ;-----------------------------------------------------------------------*/
+
+ if (!query->query) header->opcode |= 0x80;
+ if (query->aa) header->opcode |= 0x04;
+ if (query->tc) header->opcode |= 0x02;
+ if (query->rd) header->opcode |= 0x01;
+ if (query->ra) header->rcode |= 0x80;
+ if (query->ad) header->rcode |= 0x20;
+ if (query->cd) header->rcode |= 0x10;
+
+ data.size = *plen - sizeof(struct idns_header);
+ data.ptr = &buffer[sizeof(struct idns_header)];
+
+ for (size_t i = 0 ; i < query->qdcount ; i++)
+ {
+ rc = dns_encode_domain(&data,&query->questions[i]);
+ if (rc != RCODE_OKAY)
+ return rc;
+ }
+
+ /*------------------------------------------------------------
+ ; at some point we may want to encode answers, nameservers,
+ ; and additional records, but for now, we skip 'em, except
+ ; for EDNS stuff.
+ ;-----------------------------------------------------------*/
+
+ assert(query->ancount == 0);
+ assert(query->nscount == 0);
+
+ for (size_t i = 0 ; i < query->arcount ; i++)
+ {
+ switch(query->additional[i].generic.type)
+ {
+ case RR_OPT: rc = encode_rr_opt(&data,query,&query->additional[i].opt); break;
+ default: assert(0); break;
+ }
+
+ if (rc != RCODE_OKAY)
+ return rc;
+ }
+
+ *plen = (size_t)(data.ptr - buffer);
+ return RCODE_OKAY;
+}
+
+/*********************************************************************/
+
+static dns_rcode_t dns_encode_domain(
+ block_t *const restrict data,
+ const dns_question_t *const restrict pquestion
+)
+{
+ size_t len;
+ size_t delta;
+ uint8_t *start;
+ uint8_t *end;
+ uint8_t *back_ptr;
+
+ assert(pblock_okay(data));
+ assert(pquestion != NULL);
+ assert(pquestion->name != NULL);
+ assert(pquestion->class >= 1);
+ assert(pquestion->class <= 4);
+
+ len = strlen(pquestion->name);
+
+ if (pquestion->name[len - 1] != '.') /* name must be fully qualified */
+ return RCODE_NAME_ERROR;
+
+ if (data->size < len + 5) /* not enough space */
+ return RCODE_NO_MEMORY;
+
+ memcpy(&data->ptr[1],pquestion->name,len);
+ data->size -= (len + 5);
+
+ back_ptr = data->ptr;
+ start = &data->ptr[1];
+ end = &data->ptr[1];
+
+ while(len)
+ {
+ end = memchr(start,'.',len);
+ assert(end != NULL); /* must be true---checked above */
+
+ delta = (size_t)(end - start);
+ assert(delta <= len);
+
+ if (delta > 63)
+ return RCODE_NAME_ERROR;
+
+ *back_ptr = (uint8_t)delta;
+ back_ptr = end;
+ start = end + 1;
+ len -= (delta + 1);
+ }
+
+ *back_ptr = 0;
+ data->ptr = end + 1;
+
+ data->ptr[0] = (pquestion->type >> 8);
+ data->ptr[1] = (pquestion->type & 0xFF);
+ data->ptr[2] = (pquestion->class >> 8);
+ data->ptr[3] = (pquestion->class & 0xFF);
+ data->ptr += 4;
+
+ return RCODE_OKAY;
+}
+
+/*************************************************************************/
+
+static inline dns_rcode_t encode_edns0rr_nsid(
+ block_t *const restrict data,
+ const edns0_opt_t *const restrict opt
+)
+{
+ size_t newlen;
+
+ assert(pblock_okay(data));
+ assert(opt != NULL);
+ assert(opt->code == EDNS0RR_NSID);
+ assert(opt->len <= UINT16_MAX);
+
+ /*------------------------------------------------------------------------
+ ; RFC-5001 specifies that the data for an NSID RR is the hexstring of the
+ ; data, and no other meaning from the strings is to be inferred. So we
+ ; encode the data to save you from doing it.
+ ;------------------------------------------------------------------------*/
+
+ newlen = opt->len * 2;
+ if (data->size < newlen + sizeof(uint16_t) + sizeof(uint16_t))
+ return RCODE_NO_MEMORY;
+
+ char buffer[newlen + 1];
+ size_t nidx;
+ size_t i;
+
+ for (i = nidx = 0 ; i < opt->len ; i++ , nidx += 2)
+ sprintf(&buffer[nidx],"%02X",opt->data[i]);
+
+ assert(newlen == strlen(buffer));
+
+ write_uint16(data,opt->code);
+ write_uint16(data,newlen);
+ memcpy(data->ptr,buffer,newlen);
+ data->ptr += newlen;
+ data->size -= newlen;
+ return RCODE_OKAY;
+}
+
+/**********************************************************************/
+
+static inline dns_rcode_t encode_edns0rr_raw(
+ block_t *const restrict data,
+ const edns0_opt_t *const restrict opt
+)
+{
+ assert(pblock_okay(data));
+ assert(opt != NULL);
+ assert(opt->code <= UINT16_MAX);
+ assert(opt->len <= UINT16_MAX);
+
+ if (data->size < opt->len + sizeof(uint16_t) + sizeof(uint16_t))
+ return RCODE_NO_MEMORY;
+
+ write_uint16(data,opt->code);
+ write_uint16(data,opt->len);
+ memcpy(data->ptr,opt->data,opt->len);
+ data->ptr += opt->len;
+ data->size -= opt->len;
+ return RCODE_OKAY;
+}
+
+/*************************************************************************/
+
+static inline dns_rcode_t encode_rr_opt(
+ block_t *const restrict data,
+ const dns_query_t *const restrict query,
+ const dns_edns0opt_t *const restrict opt
+)
+{
+ uint8_t *prdlen;
+ size_t rdlen;
+ size_t i;
+
+ assert(pblock_okay(data));
+ assert(query != NULL);
+ assert(opt != NULL);
+ assert(opt->class == CLASS_UNKNOWN);
+ assert(opt->ttl == 0);
+ assert(opt->version == 0);
+ assert(opt->udp_payload <= UINT16_MAX);
+
+ if (data->size < 11)
+ return RCODE_NO_MEMORY;
+
+ data->ptr[0] = 00; /* root domain */
+ data->ptr++;
+ data->size--;
+
+ write_uint16(data,RR_OPT);
+ write_uint16(data,opt->udp_payload);
+ data->ptr[0] = query->rcode >> 4;
+ data->ptr[1] = opt->version;
+ data->ptr[2] = 0;
+ data->ptr[3] = 0;
+
+ if (opt->fdo) data->ptr[2] |= 0x80;
+
+ data->ptr += 4;
+ data->size -= 4;
+
+ /*----------------------------------------------------------------------
+ ; save the location for RDLEN, and set it to 0 for now. After we encode
+ ; the rest of the packet, we'll patch this with the correct length.
+ ;----------------------------------------------------------------------*/
+
+ prdlen = data->ptr;
+ write_uint16(data,0); /* place holder for now */
+
+ for (i = 0 ; i < opt->numopts; i++)
+ {
+ dns_rcode_t rc;
+
+ switch(opt->opts[i].code)
+ {
+ case EDNS0RR_NSID: rc = encode_edns0rr_nsid(data,&opt->opts[i]); break;
+ default: rc = encode_edns0rr_raw (data,&opt->opts[i]); break;
+ }
+
+ if (rc != RCODE_OKAY) return rc;
+ }
+
+ rdlen = (size_t)(data->ptr - prdlen) - sizeof(uint16_t);
+ prdlen[0] = (rdlen >> 8) & 0xFF;
+ prdlen[1] = (rdlen ) & 0xFF;
+
+ return RCODE_OKAY;
+}
+
+/*************************************************************************
+*
+* Memory allocations are done quickly. The dns_decode() routine is given a
+* block of memory to carve allocations out of (4k appears to be good eough;
+* 8k is more than enough for UDP packets) and there's no real intelligence
+* here---just a quick scheme. String information is just allocated starting
+* at the next available location (referenced in context->dest) whereas the
+* few structures that do need allocating require the free pointer to be
+* adjusted to a proper memory alignment. If you need alignments, call
+* alloc_struct(), otherwise for strings, use context->dest directly. You
+* *can* use align_memory() directly, just be sure you know what you are
+* doing.
+*
+******************************************************************************/
+
+static bool align_memory(block_t *const pool)
+{
+ size_t newsize;
+ size_t delta;
+
+ assert(pblock_okay(pool));
+
+ if (pool->size < MEM_ALIGN)
+ return false;
+
+ newsize = pool->size & MEM_MASK;
+ if (newsize == pool->size)
+ return true;
+
+ assert(newsize < pool->size);
+ delta = (newsize + MEM_ALIGN) - pool->size;
+ assert(delta < pool->size);
+
+ pool->ptr += delta;
+ pool->size -= delta;
+
+ return true;
+}
+
+/*************************************************************************/
+
+static void *alloc_struct(block_t *const pool,const size_t size)
+{
+ uint8_t *ptr;
+
+ assert(pblock_okay(pool));
+
+ if (pool->size == 0) return NULL;
+ if (!align_memory(pool)) return NULL;
+ if (pool->size < size) return NULL;
+
+ ptr = pool->ptr;
+ pool->ptr += size;
+ pool->size -= size;
+ return (void *)ptr;
+}
+
+/***********************************************************************/
+
+static inline void write_uint16(block_t *const parse,uint16_t value)
+{
+ assert(pblock_okay(parse));
+ assert(parse->size >= 2);
+
+ parse->ptr[0] = (value >> 8) & 0xFF;
+ parse->ptr[1] = (value ) & 0xFF;
+ parse->ptr += 2;
+ parse->size -= 2;
+}
+
+/***********************************************************************/
+
+static inline void write_uint32(block_t *const parse,uint32_t value)
+{
+ assert(pblock_okay(parse));
+ assert(parse->size >= 4);
+
+ parse->ptr[0] = (value >> 24) & 0xFF;
+ parse->ptr[1] = (value >> 16) & 0xFF;
+ parse->ptr[2] = (value >> 8) & 0xFF;
+ parse->ptr[3] = (value ) & 0xFF;
+ parse->ptr += 4;
+ parse->size -= 4;
+}
+
+/***********************************************************************/
+
+static inline uint16_t read_uint16(block_t *const parse)
+{
+ uint16_t val;
+
+ /*------------------------------------------------------------------------
+ ; caller is reponsible for making sure there's at least two bytes to read
+ ;------------------------------------------------------------------------*/
+
+ assert(pblock_okay(parse));
+ assert(parse->size >= 2);
+
+ val = (parse->ptr[0] << 8)
+ | (parse->ptr[1] );
+ parse->ptr += 2;
+ parse->size -= 2;
+ return val;
+}
+
+/********************************************************************/
+
+static inline uint32_t read_uint32(block_t *const parse)
+{
+ uint32_t val;
+
+ /*------------------------------------------------------------------------
+ ; caller is reponsible for making sure there's at least four bytes to read
+ ;------------------------------------------------------------------------*/
+
+ assert(pblock_okay(parse));
+ assert(parse->size >= 4);
+
+ val = (parse->ptr[0] << 24)
+ | (parse->ptr[1] << 16)
+ | (parse->ptr[2] << 8)
+ | (parse->ptr[3] );
+ parse->ptr += 4;
+ parse->size -= 4;
+ return val;
+}
+
+/********************************************************************/
+
+static dns_rcode_t read_raw(
+ idns_context *const restrict data,
+ uint8_t **restrict result,
+ const size_t len
+)
+{
+ assert(context_okay(data));
+ assert(result != NULL);
+
+ if (len > 0)
+ {
+ if (len > data->parse.size)
+ return RCODE_FORMAT_ERROR;
+
+ /*--------------------------------------------------------------------
+ ; Called when we don't know the contents of the data; it's aligned so
+ ; that if the data is actually structured, it can probably be read
+ ; directly by the clients of this code.
+ ;--------------------------------------------------------------------*/
+
+ if (!align_memory(&data->dest))
+ return RCODE_NO_MEMORY;
+
+ if (len > data->dest.size)
+ return RCODE_NO_MEMORY;
+
+ *result = data->dest.ptr;
+ memcpy(data->dest.ptr,data->parse.ptr,len);
+ data->parse.ptr += len;
+ data->parse.size -= len;
+ data->dest.ptr += len;
+ data->dest.size -= len;
+ }
+ else
+ *result = NULL;
+
+ return RCODE_OKAY;
+}
+
+/********************************************************************/
+
+static dns_rcode_t read_string(
+ idns_context *const restrict data,
+ const char **restrict result
+)
+{
+ size_t len;
+
+ assert(context_okay(data));
+ assert(result != NULL);
+
+ len = *data->parse.ptr;
+
+ if (data->dest.size < len + 1) /* adjust for NUL byte */
+ return RCODE_NO_MEMORY;
+
+ if (data->parse.size < len + 1) /* adjust for length byte */
+ return RCODE_FORMAT_ERROR;
+
+ *result = (char *)data->dest.ptr;
+ memcpy(data->dest.ptr,&data->parse.ptr[1],len);
+
+ data->parse.ptr += (len + 1);
+ data->parse.size -= (len + 1);
+ data->dest.ptr += len;
+ data->dest.size -= len;
+ *data->dest.ptr++ = '\0';
+ data->dest.size--;
+
+ return RCODE_OKAY;
+}
+
+/********************************************************************/
+
+static dns_rcode_t read_domain(
+ idns_context *const restrict data,
+ const char **restrict result
+)
+{
+ block_t *parse = &data->parse;
+ block_t tmp;
+ size_t len;
+ int loop; /* loop detection */
+
+ assert(context_okay(data));
+ assert(result != NULL);
+
+ *result = (char *)data->dest.ptr;
+ loop = 0;
+
+ do
+ {
+ /*----------------------------
+ ; read in a domain segment
+ ;-----------------------------*/
+
+ if (*parse->ptr < 64)
+ {
+ len = *parse->ptr;
+
+ if (parse->size < len + 1)
+ return RCODE_FORMAT_ERROR;
+
+ if (data->dest.size < len)
+ return RCODE_NO_MEMORY;
+
+ if (len)
+ {
+ memcpy(data->dest.ptr,&parse->ptr[1],len);
+ parse->ptr += (len + 1);
+ parse->size -= (len + 1);
+ }
+
+ data->dest.size -= (len + 1);
+ data->dest.ptr += len;
+ *data->dest.ptr++ = '.';
+ }
+
+ /*------------------------------------------
+ ; compressed segment---follow the pointer
+ ;------------------------------------------*/
+
+ else if (*parse->ptr >= 192)
+ {
+ if (++loop == 256)
+ return RCODE_FORMAT_ERROR;
+
+ if (parse->size < 2)
+ return RCODE_FORMAT_ERROR;
+
+ len = read_uint16(parse) & 0x3FFF;
+
+ if (len >= data->packet.size)
+ return RCODE_FORMAT_ERROR;
+
+ tmp.ptr = &data->packet.ptr[len];
+ tmp.size = data->packet.size - (size_t)(tmp.ptr - data->packet.ptr);
+ parse = &tmp;
+ }
+
+ /*-----------------------------------------------------------------------
+ ; EDNS0 extended labeles, RFC-2671; the only extension proposed so far,
+ ; RFC-2673, was changed from Proposed to Experimental in RFC-3363, so
+ ; I'm not including support for it at this time.
+ ;-----------------------------------------------------------------------*/
+
+ else if ((*parse->ptr >= 64) && (*parse->ptr <= 127))
+ return RCODE_FORMAT_ERROR;
+
+ /*------------------------------------
+ ; reserved for future developments
+ ;------------------------------------*/
+
+ else
+ return RCODE_FORMAT_ERROR;
+ } while(*parse->ptr);
+
+ parse->ptr++;
+ parse->size--;
+ *data->dest.ptr++ = '\0';
+ data->dest.size--;
+
+ return RCODE_OKAY;
+}
+
+/********************************************************************/
+
+static inline dns_rcode_t decode_edns0rr_nsid(
+ idns_context *const restrict data,
+ edns0_opt_t *const restrict opt
+)
+{
+ static const char hexdigits[] = "0123456789ABCDEF";
+
+ if (opt->len % 2 == 1)
+ return RCODE_FORMAT_ERROR;
+
+ if (data->dest.size < opt->len / 2)
+ return RCODE_NO_MEMORY;
+
+ for (size_t i = 0 ; i < opt->len ; i += 2)
+ {
+ const char *phexh;
+ const char *phexl;
+
+ if (!isxdigit(data->parse.ptr[i])) return RCODE_FORMAT_ERROR;
+ if (!isxdigit(data->parse.ptr[i+1])) return RCODE_FORMAT_ERROR;
+
+ phexh = memchr(hexdigits,toupper(data->parse.ptr[i]) ,16);
+ phexl = memchr(hexdigits,toupper(data->parse.ptr[i+1]),16);
+
+ /*------------------------------------------------------------------
+ ; phexh and phexl should not be NULL, unless isxdigit() is buggy, and
+ ; that is something I'm not assuming.
+ ;--------------------------------------------------------------------*/
+
+ assert(phexh != NULL);
+ assert(phexl != NULL);
+
+ *data->dest.ptr = ((phexh - hexdigits) << 4)
+ | ((phexl - hexdigits) );
+ data->dest.ptr++;
+ data->dest.size--;
+ }
+
+ data->parse.ptr += opt->len;
+ data->parse.size -= opt->len;
+ opt->len /= 2;
+ return RCODE_OKAY;
+}
+
+/***********************************************************************/
+
+static inline dns_rcode_t decode_edns0rr_raw(
+ idns_context *const restrict data,
+ edns0_opt_t *const restrict opt
+)
+{
+ if (data->dest.size < opt->len)
+ return RCODE_NO_MEMORY;
+
+ memcpy(data->dest.ptr,data->parse.ptr,opt->len);
+ data->parse.ptr += opt->len;
+ data->parse.size -= opt->len;
+ data->dest.ptr += opt->len;
+ data->dest.size -= opt->len;
+ return RCODE_OKAY;
+}
+
+/*************************************************************/
+
+static dns_rcode_t decode_question(
+ idns_context *const restrict data,
+ dns_question_t *const restrict pquest
+)
+{
+ dns_rcode_t rc;
+
+ assert(context_okay(data));
+ assert(pquest != NULL);
+
+ rc = read_domain(data,&pquest->name);
+ if (rc != RCODE_OKAY)
+ return rc;
+
+ if (data->parse.size < 4)
+ return RCODE_FORMAT_ERROR;
+
+ pquest->type = (dns_type_t) read_uint16(&data->parse);
+ pquest->class = (dns_class_t)read_uint16(&data->parse);
+
+ /*-------------------------------------------------------
+ ; OPT RRs can never be the target of a question as it's
+ ; more of a pseudo RR than a real live boy, um, RR.
+ ;--------------------------------------------------------*/
+
+ if (pquest->type == RR_OPT)
+ return RCODE_FORMAT_ERROR;
+
+ return RCODE_OKAY;
+}
+
+/************************************************************************/
+
+static inline dns_rcode_t decode_rr_soa(
+ idns_context *const restrict data,
+ dns_soa_t *const restrict psoa,
+ const size_t len
+)
+{
+ dns_rcode_t rc;
+
+ assert(context_okay(data));
+ assert(psoa != NULL);
+
+ rc = read_domain(data,&psoa->mname);
+ if (rc != RCODE_OKAY) return rc;
+ rc = read_domain(data,&psoa->rname);
+ if (rc != RCODE_OKAY) return rc;
+
+ if (len < 20)
+ return RCODE_FORMAT_ERROR;
+
+ psoa->serial = read_uint32(&data->parse);
+ psoa->refresh = read_uint32(&data->parse);
+ psoa->retry = read_uint32(&data->parse);
+ psoa->expire = read_uint32(&data->parse);
+ psoa->minimum = read_uint32(&data->parse);
+
+ return RCODE_OKAY;
+}
+
+/***********************************************************************/
+
+static inline dns_rcode_t decode_rr_a(
+ idns_context *const restrict data,
+ dns_a_t *const restrict pa,
+ const size_t len
+)
+{
+ assert(context_okay(data));
+ assert(pa != NULL);
+
+ if (len != 4) return RCODE_FORMAT_ERROR;
+ memcpy(&pa->address,data->parse.ptr,4);
+ data->parse.ptr += 4;
+ data->parse.size -= 4;
+ return RCODE_OKAY;
+}
+
+/***********************************************************************/
+
+static inline dns_rcode_t decode_rr_aaaa(
+ idns_context *const restrict data,
+ dns_aaaa_t *const restrict pa,
+ const size_t len
+)
+{
+ assert(context_okay(data));
+ assert(pa != NULL);
+
+ if (len != 16) return RCODE_FORMAT_ERROR;
+ memcpy(pa->address.s6_addr,data->parse.ptr,16);
+ data->parse.ptr += 16;
+ data->parse.size -= 16;
+ return RCODE_OKAY;
+}
+
+/**********************************************************************/
+
+static inline dns_rcode_t decode_rr_wks(
+ idns_context *const restrict data,
+ dns_wks_t *const restrict pwks,
+ const size_t len
+)
+{
+ assert(context_okay(data));
+ assert(pwks != NULL);
+
+ if (len < 6) return RCODE_FORMAT_ERROR;
+
+ memcpy(&pwks->address,data->parse.ptr,4);
+ data->parse.ptr += 4;
+ data->parse.size -= 4;
+ pwks->protocol = read_uint16(&data->parse);
+
+ pwks->numbits = len - 6;
+ return read_raw(data,&pwks->bits,pwks->numbits);
+}
+
+/*********************************************************************/
+
+static inline dns_rcode_t decode_rr_mx(
+ idns_context *const restrict data,
+ dns_mx_t *const restrict pmx,
+ const size_t len
+)
+{
+ assert(context_okay(data));
+ assert(pmx != NULL);
+
+ if (len < 4) return RCODE_FORMAT_ERROR;
+
+ pmx->preference = read_uint16(&data->parse);
+ return read_domain(data,&pmx->exchange);
+}
+
+/**********************************************************************/
+
+static inline dns_rcode_t decode_rr_txt(
+ idns_context *const restrict data,
+ dns_txt_t *const restrict ptxt,
+ const size_t len
+)
+{
+ block_t tmp;
+ size_t worklen;
+ size_t items;
+ size_t slen;
+
+ assert(context_okay(data));
+ assert(ptxt != NULL);
+
+ /*--------------------------------------------------------------------
+ ; collapse multiple strings (which are allowed per the spec) into one
+ ; large string. Cache the length as well, as some records might prefer
+ ; the length to be there (in case of binary data)
+ ;---------------------------------------------------------------------*/
+
+ tmp = data->parse;
+ worklen = len;
+ ptxt->len = 0;
+
+ for (items = 0 ; worklen ; )
+ {
+ slen = *tmp.ptr + 1;
+
+ if (tmp.size < slen)
+ return RCODE_FORMAT_ERROR;
+
+ items++;
+ ptxt->len += slen - 1;
+ tmp.ptr += slen;
+ tmp.size -= slen;
+ worklen -= slen;
+ }
+
+ ptxt->text = (const char *)data->dest.ptr;
+
+ for (size_t i = 0 ; i < items ; i++)
+ {
+ slen = *data->parse.ptr;
+ if (data->dest.size < slen)
+ return RCODE_NO_MEMORY;
+
+ memcpy(data->dest.ptr,&data->parse.ptr[1],slen);
+ data->dest.ptr += slen;
+ data->dest.size -= slen;
+ data->parse.ptr += (slen + 1);
+ data->parse.size -= (slen + 1);
+ }
+
+ if (data->dest.size == 0)
+ return RCODE_NO_MEMORY;
+
+ *data->dest.ptr++ = '\0';
+ data->dest.size--;
+
+ return RCODE_OKAY;
+}
+
+/**********************************************************************/
+
+static inline dns_rcode_t decode_rr_hinfo(
+ idns_context *const restrict data,
+ dns_hinfo_t *const restrict phinfo
+)
+{
+ dns_rcode_t rc;
+
+ assert(context_okay(data));
+ assert(phinfo != NULL);
+
+ rc = read_string(data,&phinfo->cpu);
+ if (rc != RCODE_OKAY) return rc;
+ rc = read_string(data,&phinfo->os);
+ return rc;
+}
+
+/**********************************************************************/
+
+static inline dns_rcode_t decode_rr_srv(
+ idns_context *const restrict data,
+ dns_srv_t *const restrict psrv,
+ const size_t len
+)
+{
+ assert(context_okay(data));
+ assert(psrv != NULL);
+
+ if (len < 7)
+ return RCODE_FORMAT_ERROR;
+
+ psrv->priority = read_uint16(&data->parse);
+ psrv->weight = read_uint16(&data->parse);
+ psrv->port = read_uint16(&data->parse);
+ return read_domain(data,&psrv->target);
+}
+
+/**********************************************************************/
+
+static inline dns_rcode_t decode_rr_naptr(
+ idns_context *const restrict data,
+ dns_naptr_t *const restrict pnaptr,
+ const size_t len
+)
+{
+ dns_rcode_t rc;
+
+ assert(context_okay(data));
+ assert(pnaptr != NULL);
+
+ if (len < 4)
+ return RCODE_FORMAT_ERROR;
+
+ pnaptr->order = read_uint16(&data->parse);
+ pnaptr->preference = read_uint16(&data->parse);
+
+ rc = read_string(data,&pnaptr->flags);
+ if (rc != RCODE_OKAY) return rc;
+ rc = read_string(data,&pnaptr->services);
+ if (rc != RCODE_OKAY) return rc;
+ rc = read_string(data,&pnaptr->regexp);
+ if (rc != RCODE_OKAY) return rc;
+ return read_domain(data,&pnaptr->replacement);
+}
+
+/********************************************************************/
+
+static inline dns_rcode_t decode_rr_sig(
+ idns_context *const restrict data,
+ dns_sig_t *const restrict psig,
+ const size_t len
+)
+{
+ uint8_t *start;
+ size_t sofar;
+ dns_rcode_t rc;
+
+ assert(context_okay(data));
+ assert(psig != NULL);
+
+ if (len < 18)
+ return RCODE_FORMAT_ERROR;
+
+ /*-----------------------------------------------------------------------
+ ; The signature portion doesn't have a length code. Because of that, we
+ ; need to track how much data is left so we can pull it out. We record
+ ; the start of the parsing area, and once we get past the signer, we can
+ ; calculate the remainder data to pull out.
+ ;------------------------------------------------------------------------*/
+
+ start = data->parse.ptr;
+
+ psig->covered = read_uint16(&data->parse);
+ psig->algorithm = *data->parse.ptr++; data->parse.size--;
+ psig->labels = *data->parse.ptr++; data->parse.size--;
+ psig->originttl = read_uint32(&data->parse);
+ psig->sigexpire = read_uint32(&data->parse);
+ psig->timesigned = read_uint32(&data->parse);
+ psig->keyfootprint = read_uint16(&data->parse);
+
+ rc = read_domain(data,&psig->signer);
+ if (rc != RCODE_OKAY) return rc;
+
+ sofar = (size_t)(data->parse.ptr - start);
+ if (sofar > len) return RCODE_FORMAT_ERROR;
+
+ psig->sigsize = len - sofar;
+ return read_raw(data,&psig->signature,psig->sigsize);
+}
+
+/******************************************************************/
+
+static inline dns_rcode_t decode_rr_minfo(
+ idns_context *const restrict data,
+ dns_minfo_t *const restrict pminfo
+)
+{
+ dns_rcode_t rc;
+
+ assert(context_okay(data));
+ assert(pminfo != NULL);
+
+ rc = read_domain(data,&pminfo->rmailbx);
+ if (rc != RCODE_OKAY) return rc;
+ return read_domain(data,&pminfo->emailbx);
+}
+
+/*****************************************************************/
+
+static dns_rcode_t dloc_double(idns_context *const restrict,double *const restrict) __attribute__ ((nonnull));
+
+static dns_rcode_t dloc_double(
+ idns_context *const restrict data,
+ double *const restrict pvalue
+)
+{
+ size_t len;
+
+ assert(context_okay(data));
+ assert(pvalue != NULL);
+
+ len = *data->parse.ptr;
+ if (len > data->parse.size - 1)
+ return RCODE_FORMAT_ERROR;
+
+ char buffer[len + 1];
+ memcpy(buffer,&data->parse.ptr[1],len);
+ buffer[len++] = '\0';
+
+ data->parse.ptr += len;
+ data->parse.size -= len;
+
+ errno = 0;
+ *pvalue = strtod(buffer,NULL);
+ if (errno) return RCODE_FORMAT_ERROR;
+
+ return RCODE_OKAY;
+}
+
+/****************************************************************/
+
+static void dgpos_angle(dnsgpos_angle *const restrict,double) __attribute__ ((nonnull(1)));
+
+static void dgpos_angle(
+ dnsgpos_angle *const restrict pa,
+ double v
+)
+{
+ double ip;
+
+ v = modf(v,&ip) * 60.0; pa->deg = ip;
+ v = modf(v,&ip) * 60.0; pa->min = ip;
+ v = modf(v,&ip) * 1000.0; pa->sec = ip;
+ pa->frac = v;
+}
+
+/*****************************************************************/
+
+static inline dns_rcode_t decode_rr_gpos(
+ idns_context *const restrict data,
+ dns_gpos_t *const restrict pgpos
+)
+{
+ dns_rcode_t rc;
+ double lat;
+ double lng;
+
+ assert(context_okay(data));
+ assert(pgpos != NULL);
+
+ rc = dloc_double(data,&lng);
+ if (rc != RCODE_OKAY) return rc;
+ rc = dloc_double(data,&lat);
+ if (rc != RCODE_OKAY) return rc;
+
+ if (lng < 0.0)
+ {
+ pgpos->longitude.nw = true;
+ lng = fabs(lng);
+ }
+
+ if (lat >= 0.0)
+ pgpos->latitude.nw = true;
+ else
+ lat = fabs(lat);
+
+ dgpos_angle(&pgpos->longitude,lng);
+ dgpos_angle(&pgpos->latitude, lat);
+
+ return dloc_double(data,&pgpos->altitude);
+}
+
+/**************************************************************************
+*
+* You really, no, I mean it, *REALLY* need to read RFC-1876 to understand
+* all the crap that's going on for deciphering RR_LOC.
+*
+**************************************************************************/
+
+#define LOC_BIAS (((unsigned long)INT32_MAX) + 1uL)
+#define LOC_LAT_MAX ((unsigned long)( 90uL * 3600000uL))
+#define LOC_LNG_MAX ((unsigned long)(180uL * 3600000uL))
+#define LOC_ALT_BIAS (10000000L)
+
+static int dloc_scale(unsigned long *const restrict,const int) __attribute__ ((nonnull(1)));
+
+static int dloc_scale(
+ unsigned long *const restrict presult,
+ const int scale
+)
+{
+ int spow;
+ int smul;
+
+ assert(presult != NULL);
+
+ smul = scale >> 4;
+ spow = scale & 0x0F;
+
+ if ((spow > 9) || (smul > 9))
+ return RCODE_FORMAT_ERROR;
+
+ *presult = (unsigned long)(pow(10.0,spow) * smul);
+ return RCODE_OKAY;
+}
+
+/**************************************************************/
+
+static void dloc_angle(dnsgpos_angle *const restrict,const long) __attribute__ ((nonnull(1)));
+
+static void dloc_angle(
+ dnsgpos_angle *const restrict pa,
+ const long v
+)
+{
+ ldiv_t partial;
+
+ assert(pa != NULL);
+
+ partial = ldiv(v,1000L);
+ pa->frac = partial.rem;
+ partial = ldiv(partial.quot,60L);
+ pa->sec = partial.rem;
+ partial = ldiv(partial.quot,60L);
+ pa->min = partial.rem;
+ pa->deg = partial.quot;
+}
+
+/*************************************************************/
+
+static inline dns_rcode_t decode_rr_loc(
+ idns_context *const restrict data,
+ dns_loc_t *const restrict ploc,
+ const size_t len
+)
+{
+ dns_rcode_t rc;
+ unsigned long lat;
+ unsigned long lng;
+
+ assert(context_okay(data));
+ assert(ploc != NULL);
+
+ if (len < 16) return RCODE_FORMAT_ERROR;
+
+ ploc->version = data->parse.ptr[0];
+
+ if (ploc->version != 0)
+ return RCODE_FORMAT_ERROR;
+
+ rc = dloc_scale(&ploc->size,data->parse.ptr[1]);
+ if (rc != RCODE_OKAY) return rc;
+ rc = dloc_scale(&ploc->horiz_pre,data->parse.ptr[2]);
+ if (rc != RCODE_OKAY) return rc;
+ rc = dloc_scale(&ploc->vert_pre,data->parse.ptr[3]);
+ if (rc != RCODE_OKAY) return rc;
+
+ data->parse.ptr += 4;
+
+ lat = read_uint32(&data->parse);
+ lng = read_uint32(&data->parse);
+ ploc->altitude = read_uint32(&data->parse) - LOC_ALT_BIAS;
+
+ if (lat >= LOC_BIAS) /* north */
+ {
+ ploc->latitude.nw = true;
+ lat -= LOC_BIAS;
+ }
+ else
+ lat = LOC_BIAS - lat;
+
+ if (lng >= LOC_BIAS) /* east */
+ lng -= LOC_BIAS;
+ else
+ {
+ ploc->longitude.nw = true;
+ lng = LOC_BIAS - lng;
+ }
+
+ if (lat > LOC_LAT_MAX)
+ return RCODE_FORMAT_ERROR;
+
+ if (lng > LOC_LNG_MAX)
+ return RCODE_FORMAT_ERROR;
+
+ dloc_angle(&ploc->latitude ,lat);
+ dloc_angle(&ploc->longitude,lng);
+
+ return RCODE_OKAY;
+}
+
+/***************************************************************/
+
+static inline dns_rcode_t decode_rr_opt(
+ idns_context *const restrict data,
+ dns_edns0opt_t *const restrict opt,
+ const size_t len
+)
+{
+ assert(data != NULL);
+ assert(opt != NULL);
+
+ if (data->edns) /* there can be only one */
+ return RCODE_FORMAT_ERROR;
+
+ data->edns = true;
+ opt->numopts = 0;
+ opt->opts = NULL;
+
+ if (len)
+ {
+ uint8_t *scan;
+ size_t length;
+
+ assert(context_okay(data));
+ assert(len > 4);
+
+ for (scan = data->parse.ptr , opt->numopts = 0 , length = len ; length > 0 ; )
+ {
+ size_t size;
+
+ opt->numopts++;
+ size = ((scan[2] << 8) | (scan[3])) + 4;
+ scan += size;
+
+ if (size > length)
+ return RCODE_FORMAT_ERROR;
+
+ length -= size;
+ }
+
+ opt->opts = alloc_struct(&data->dest,sizeof(edns0_opt_t) * opt->numopts);
+ if (opt->opts == NULL)
+ return RCODE_NO_MEMORY;
+
+ for (size_t i = 0 ; i < opt->numopts ; i++)
+ {
+ dns_rcode_t rc;
+
+ opt->opts[i].code = read_uint16(&data->parse);
+ opt->opts[i].len = read_uint16(&data->parse);
+
+ /*-----------------------------------------------------------------
+ ; much like in read_raw(), we don't necessarily know the data we're
+ ; reading, so why not align it?
+ ;------------------------------------------------------------------*/
+
+ if (!align_memory(&data->dest))
+ return RCODE_NO_MEMORY;
+
+ opt->opts[i].data = data->dest.ptr;
+
+ switch(opt->opts[i].code)
+ {
+ case EDNS0RR_NSID: rc = decode_edns0rr_nsid(data,&opt->opts[i]); break;
+ default: rc = decode_edns0rr_raw (data,&opt->opts[i]); break;
+ }
+
+ if (rc != RCODE_OKAY) return rc;
+ }
+ }
+
+ return RCODE_OKAY;
+}
+
+/**********************************************************************/
+
+static dns_rcode_t decode_answer(
+ idns_context *const restrict data,
+ dns_answer_t *const restrict pans
+)
+{
+ size_t len;
+ size_t rest;
+ dns_rcode_t rc;
+
+ assert(context_okay(data));
+ assert(pans != NULL);
+
+ rc = read_domain(data,&pans->generic.name);
+ if (rc != RCODE_OKAY)
+ return rc;
+
+ if (data->parse.size < 10)
+ return RCODE_FORMAT_ERROR;
+
+ pans->generic.type = read_uint16(&data->parse);
+
+ /*-----------------------------------------------------------------
+ ; RR_OPT is annoying, since the defined class and ttl fields are
+ ; interpreted completely differently. Thanks a lot, Paul Vixie! So we
+ ; need to special case this stuff a bit.
+ ;----------------------------------------------------------------*/
+
+ if (pans->generic.type == RR_OPT)
+ {
+ pans->generic.class = CLASS_UNKNOWN;
+ pans->generic.ttl = 0;
+ pans->opt.udp_payload = read_uint16(&data->parse);
+ data->response->rcode = (data->parse.ptr[0] << 4) | data->response->rcode;
+
+ if (data->parse.ptr[1] != 0) /* version */
+ return RCODE_FORMAT_ERROR;
+
+ if ((data->parse.ptr[2] & 0x80) == 0x80) /* RFC-3225 */
+ pans->opt.fdo = true;
+ if ((data->parse.ptr[2] & 0x7F) != 0)
+ return RCODE_FORMAT_ERROR;
+ if (data->parse.ptr[3] != 0)
+ return RCODE_FORMAT_ERROR;
+
+ data->parse.ptr += 4;
+ data->parse.size -= 4;
+ }
+ else
+ {
+ pans->generic.class = read_uint16(&data->parse);
+ pans->generic.ttl = read_uint32(&data->parse);
+ }
+
+ len = read_uint16(&data->parse);
+ rest = data->packet.size - (data->parse.ptr - data->packet.ptr);
+
+ if (len > rest)
+ return RCODE_FORMAT_ERROR;
+
+ switch(pans->generic.type)
+ {
+ case RR_A: return decode_rr_a (data,&pans->a ,len);
+ case RR_SOA: return decode_rr_soa (data,&pans->soa ,len);
+ case RR_NAPTR: return decode_rr_naptr(data,&pans->naptr,len);
+ case RR_AAAA: return decode_rr_aaaa (data,&pans->aaaa ,len);
+ case RR_SRV: return decode_rr_srv (data,&pans->srv ,len);
+ case RR_WKS: return decode_rr_wks (data,&pans->wks ,len);
+ case RR_GPOS: return decode_rr_gpos (data,&pans->gpos);
+ case RR_LOC: return decode_rr_loc (data,&pans->loc ,len);
+ case RR_OPT: return decode_rr_opt (data,&pans->opt ,len);
+
+ /*----------------------------------------------------------------------
+ ; The following record types all share the same structure (although the
+ ; last field name is different, depending upon the record), so they can
+ ; share the same call site. It's enough to shave some space in the
+ ; executable while being a cheap and non-obscure size optimization, or
+ ; a gross hack, depending upon your view.
+ ;----------------------------------------------------------------------*/
+
+ case RR_PX:
+ case RR_RP:
+ case RR_MINFO: return decode_rr_minfo(data,&pans->minfo);
+
+ case RR_AFSDB:
+ case RR_RT:
+ case RR_MX: return decode_rr_mx(data,&pans->mx,len);
+
+ case RR_NSAP:
+ case RR_ISDN:
+ case RR_HINFO: return decode_rr_hinfo(data,&pans->hinfo);
+
+ case RR_X25:
+ case RR_SPF:
+ case RR_TXT: return decode_rr_txt(data,&pans->txt,len);
+
+ case RR_NSAP_PTR:
+ case RR_MD:
+ case RR_MF:
+ case RR_MB:
+ case RR_MG:
+ case RR_MR:
+ case RR_NS:
+ case RR_PTR:
+ case RR_CNAME: return read_domain(data,&pans->cname.cname);
+
+ case RR_NULL:
+ default:
+ pans->x.size = len;
+ return read_raw(data,&pans->x.rawdata,len);
+ }
+
+ assert(0);
+ return RCODE_OKAY;
+}
+
+/***********************************************************************/
+
+dns_rcode_t dns_decode(
+ dns_decoded_t *const restrict presponse,
+ size_t *const restrict prsize,
+ const dns_packet_t *const restrict buffer,
+ const size_t len
+)
+{
+ const struct idns_header *header;
+ dns_query_t *response;
+ idns_context context;
+ dns_rcode_t rc;
+
+ assert(presponse != NULL);
+ assert(prsize != NULL);
+ assert(*prsize >= sizeof(dns_query_t));
+ assert(buffer != NULL);
+ assert(len >= sizeof(struct idns_header));
+
+ context.packet.ptr = (uint8_t *)buffer;
+ context.packet.size = len;
+ context.parse.ptr = &context.packet.ptr[sizeof(struct idns_header)];
+ context.parse.size = len - sizeof(struct idns_header);
+ context.dest.ptr = (uint8_t *)presponse;
+ context.dest.size = *prsize;
+ context.edns = false;
+
+ /*--------------------------------------------------------------------------
+ ; we use the block of data given to store the results. context.dest
+ ; contains this block and allocations are doled out from this. This odd
+ ; bit here sets the structure to the start of the block we're using, and
+ ; then "allocates" the size f the structure in the context variable. I do
+ ; this as a test of the allocation routines when the address is already
+ ; aligned (an assumption I'm making)---the calls to assert() ensure this
+ ; behavior.
+ ;--------------------------------------------------------------------------*/
+
+ response = (dns_query_t *)context.dest.ptr;
+ context.response = alloc_struct(&context.dest,sizeof(dns_query_t));
+
+ assert(context.response != NULL);
+ assert(context.response == response);
+
+ memset(response,0,sizeof(dns_query_t));
+ response->questions = NULL;
+ response->answers = NULL;
+ response->nameservers = NULL;
+ response->additional = NULL;
+
+ header = (struct idns_header *)buffer;
+
+ if ((header->rcode & 0x40) != 0x00) /* Z bit must be zero */
+ return RCODE_FORMAT_ERROR;
+
+ response->id = ntohs(header->id);
+ response->opcode = (header->opcode >> 3) & 0x0F;
+ response->query = (header->opcode & 0x80) != 0x80;
+ response->aa = (header->opcode & 0x04) == 0x04;
+ response->tc = (header->opcode & 0x02) == 0x02;
+ response->rd = (header->opcode & 0x01) == 0x01;
+ response->ra = (header->rcode & 0x80) == 0x80;
+ response->ad = (header->rcode & 0x20) == 0x20;
+ response->cd = (header->rcode & 0x10) == 0x10;
+ response->rcode = (header->rcode & 0x0F);
+ response->qdcount = ntohs(header->qdcount);
+ response->ancount = ntohs(header->ancount);
+ response->nscount = ntohs(header->nscount);
+ response->arcount = ntohs(header->arcount);
+
+ response->questions = alloc_struct(&context.dest,response->qdcount * sizeof(dns_question_t));
+ response->answers = alloc_struct(&context.dest,response->ancount * sizeof(dns_answer_t));
+ response->nameservers = alloc_struct(&context.dest,response->nscount * sizeof(dns_answer_t));
+ response->additional = alloc_struct(&context.dest,response->arcount * sizeof(dns_answer_t));
+
+ if (
+ (response->qdcount && (response->questions == NULL))
+ || (response->ancount && (response->answers == NULL))
+ || (response->nscount && (response->nameservers == NULL))
+ || (response->arcount && (response->additional == NULL))
+ )
+ {
+ return RCODE_NO_MEMORY;
+ }
+
+ for (size_t i = 0 ; i < response->qdcount ; i++)
+ {
+ rc = decode_question(&context,&response->questions[i]);
+ if (rc != RCODE_OKAY)
+ return rc;
+ }
+
+ for (size_t i = 0 ; i < response->ancount ; i++)
+ {
+ rc = decode_answer(&context,&response->answers[i]);
+ if (rc != RCODE_OKAY)
+ return rc;
+ }
+
+ /*-------------------------------------------------------------
+ ; RR OPT can only appear once, and only in the additional info
+ ; section. Check that we haven't seen one before.
+ ;-------------------------------------------------------------*/
+
+ if (context.edns) return RCODE_FORMAT_ERROR;
+
+ for (size_t i = 0 ; i < response->nscount ; i++)
+ {
+ rc = decode_answer(&context,&response->nameservers[i]);
+ if (rc != RCODE_OKAY)
+ return rc;
+ }
+
+ if (context.edns) return RCODE_FORMAT_ERROR;
+
+ for (size_t i = 0 ; i < response->arcount ; i++)
+ {
+ rc = decode_answer(&context,&response->additional[i]);
+ if (rc != RCODE_OKAY)
+ return rc;
+ }
+
+ *prsize = (size_t)(context.dest.ptr - (uint8_t *)presponse);
+ return RCODE_OKAY;
+}
+
+/************************************************************************/
diff -r 3bd5c2e9e8ac -r fee6b517c6d4 contrib/spcdns/src/dns.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/spcdns/src/dns.h Wed Sep 19 15:25:04 2012 +0300
@@ -0,0 +1,990 @@
+/*************************************************************************
+*
+* Copyright 2010 by Sean Conner. All Rights Reserved.
+*
+* 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 3 of the License, or (at your
+* option) any later version.
+*
+* This library is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+* License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with this library; if not, see <http://www.gnu.org/licenses/>.
+*
+**************************************************************************/
+
+/*************************************************************************
+*
+* Definitions for all things related to the DNS protocol (and not to the
+* network transport thereof---that's for another episode).
+*
+* I've scoured the Internet and I think I've located every DNS RR type that
+* exists. And for the majority of them, I've made an in-memory
+* representation of said record for easy access to the contents (for when I
+* do get around to decoding them from their wire representation). For
+* records that I do not decode (and you'll need to check codec.c to see
+* which ones aren't being decoded) you'll get back a dns_x_t, which has the
+* common portion of the RR decoded (which includes the ID, type, class and
+* TTL) plus the remainder of the raw packet.
+*
+* My eventual intent is to decode those records that I can find definitions
+* for, and decipher the sometimes dry and dense RFCs that describe said RRs.
+* I'm well on my way with support for about half the known records (which
+* includes the ones most likely to be found in 99% of all zone files).
+*
+* This file assumes C99. You must include the following files before
+* including this one:
+*
+* #include <stdbool.h>
+* #include <stdint.h>
+* #include <stddef.h>
+* #incldue <arpa/inet.h>
+*
+***************************************************************************/
+
+#ifndef DNS_H
+#define DNS_H
+
+#ifdef __cplusplus
+# define class dclass
+# define restrict
+ extern "C" {
+#endif
+
+#ifndef __GNUC__
+# define __attribute__(x)
+#endif
+
+/****************************************************************************
+* Buffers passed to these routines should be declared as one of these two
+* types with one of the given sizes below, depending upon what the buffer is
+* being used for. This is to ensure things work out fine and don't blow up
+* (like a segfault). The 4K size *should* be okay for UDP packets, but if
+* you are worried, 8K is more than enough to handle responses from UDP.
+* Larger sizes may be required for TCP.
+*
+* A declaration would looke something like:
+*
+* dns_packet_t query_packet [DNS_BUFFER_UDP];
+* dns_decoded_t decoded_response[DNS_DECODEBUF_4K];
+*
+* Alternatively, you can do this:
+*
+* dns_packet_t *pquery_packet;
+* dns_decoded_t *pdecoded_response;
+*
+* pquery_packet = malloc(MAX_DNS_QUERY_SIZE);
+* pdecoded_response = malloc(4192);
+*
+*************************************************************************/
+
+typedef uintptr_t dns_packet_t;
+typedef uintptr_t dns_decoded_t;
+
+#define DNS_BUFFER_UDP ( 512uL / sizeof(dns_packet_t))
+#define DNS_DECODEBUF_4K ( 4096uL / sizeof(dns_decoded_t))
+#define DNS_DECODEBUF_8K ( 8192uL / sizeof(dns_decoded_t))
+#define DNS_DECODEBUF_16k (16384uL / sizeof(dns_decoded_t))
+
+/************************************************************************
+* Various upper limits in the DNS protocol
+************************************************************************/
+
+#define MAX_DNS_QUERY_SIZE 512
+#define MAX_DOMAIN_SEGMENT 64
+#define MAX_STRING_LEN 256
+#define MAX_UDP_PACKET_SIZE 1492
+
+/***************************************************************************
+* I've specified where each RR, Class and error codes are defined. Also,
+* for the RRs, I've marked if I have decode support as well as experimental
+* and obsolete information as follows:
+*
+* + Decoding support
+* O Obsolete
+* E Experimental
+*
+***************************************************************************/
+
+typedef enum dns_type
+{
+ RR_A = 1, /* IPv4 Address + RFC-1035 */
+ RR_NS = 2, /* Name server + RFC-1035 */
+ RR_MD = 3, /* Mail Destination O+ RFC-1035 */
+ RR_MF = 4, /* Mail Forwarder O+ RFC-1035 */
+ RR_CNAME = 5, /* Canonical name + RFC-1035 */
+ RR_SOA = 6, /* Start of Authority + RFC-1035 */
+ RR_MB = 7, /* Mailbox E+ RFC-1035 */
+ RR_MG = 8, /* Mailgroup E+ RFC-1035 */
+ RR_MR = 9, /* Mailrename E+ RFC-1035 */
+ RR_NULL = 10, /* NULL resource E+ RFC-1035 */
+ RR_WKS = 11, /* Well Known Service + RFC-1035 */
+ RR_PTR = 12, /* Pointer + RFC-1035 */
+ RR_HINFO = 13, /* Host Info + RFC-1035 */
+ RR_MINFO = 14, /* Mailbox/mail list info + RFC-1035 */
+ RR_MX = 15, /* Mail Exchange + RFC-1035 */
+ RR_TXT = 16, /* Text + RFC-1035 */
+ RR_RP = 17, /* Responsible Person + RFC-1183 */
+ RR_AFSDB = 18, /* Andrew File System DB + RFC-1183 RFC-5864 */
+ RR_X25 = 19, /* X.25 address, route binding + RFC-1183 */
+ RR_ISDN = 20, /* ISDN address, route binding + RFC-1183 */
+ RR_RT = 21, /* Route Through + RFC-1183 */
+ RR_NSAP = 22, /* Network Service Access Proto + RFC-1348 RFC-1706 */
+ RR_NSAP_PTR = 23, /* NSAP Pointer + RFC-1348 */
+ RR_SIG = 24, /* Signature RFC-2065 RFC-2535 RFC-3755 RFC-4034 */
+ RR_KEY = 25, /* Key RFC-2065 RFC-2535 RFC-3755 RFC-4034 */
+ RR_PX = 26, /* X.400 mail mapping + RFC-2163 */
+ RR_GPOS = 27, /* Geographical position O+ RFC-1712 */
+ RR_AAAA = 28, /* IPv6 Address + RFC-1886 RFC-3596 */
+ RR_LOC = 29, /* Location + RFC-1876 */
+ RR_NXT = 30, /* Next RR RFC-2065 RFC-2535 RFC-3755 */
+ RR_EID = 31, /* Endpoint Identifier ??? */
+ RR_NIMLOC = 32, /* Nimrod Locator ??? */
+ RR_SRV = 33, /* Service + RFC-2782 */
+ RR_ATM = 34, /* ATM Address ??? */
+ RR_NAPTR = 35, /* Naming Authority Pointer + RFC-2168 RFC-2915 RFC-3403 */
+ RR_KX = 36, /* Key Exchange RFC-2230 */
+ RR_CERT = 37, /* Certification RFC-4398 */
+ RR_A6 = 38, /* IPv6 Address RFC-2874 RFC-3658 */
+ RR_DNAME = 39, /* Non-terminal DNAME (IPv6) RFC-2672 */
+ RR_SINK = 40, /* Kitchen sink E ??? */
+ RR_OPT = 41, /* EDNS0 option (meta-RR) + RFC-2671 */
+ RR_APL = 42, /* Address Prefix List RFC-3123 */
+ RR_DS = 43, /* Delegation Signer RFC-3658 RFC-4034 */
+ RR_SSHFP = 44, /* SSH Key Fingerprint RFC-4255 */
+ RR_ISECKEY = 45, /* IP Security Key RFC-4025 */
+ RR_RRSIG = 46, /* Resource Record Signature RFC-3755 RFC-4034 */
+ RR_NSEC = 47, /* Next Security Record RFC-3755 RFC-4034 */
+ RR_DNSKEY = 48, /* DNS Security Key RFC-3755 RFC-4034 */
+ RR_DHCID = 49, /* DHCID RFC-4701 */
+ RR_NSEC3 = 50, /* NSEC3 RFC-5155 */
+ RR_NSEC3PARAM = 51, /* NSEC3PARAM RFC-5155 */
+ RR_HIP = 55, /* Host Identity Protocol RFC-5205 */
+ RR_NINFO = 56, /* NINFO ??? */
+ RR_RKEY = 57, /* RKEY ??? */
+ RR_TALINK = 58, /* Trust Anchor Link ??? */
+ RR_SPF = 99, /* Sender Policy Framework + RFC-4408 */
+ RR_UINFO = 100, /* IANA Reserved ??? */
+ RR_UID = 101, /* IANA Reserved ??? */
+ RR_GID = 102, /* IANA Reserved ??? */
+ RR_UNSPEC = 103, /* IANA Reserved ??? */
+
+ /* Query types, >= 128 */
+
+ RR_TKEY = 249, /* Transaction Key RFC-2930 */
+ RR_TSIG = 250, /* Transaction Signature RFC-2845 */
+ RR_IXFR = 251, /* Incremental zone transfer RFC-1995 */
+ RR_AXFR = 252, /* Transfer of zone RFC-1035 RFC-5936 */
+ RR_MAILB = 253, /* Mailbox related records RFC-1035 */
+ RR_MAILA = 254, /* Mail agent RRs (obsolete) O RFC-1035 */
+ RR_ANY = 255, /* All records RFC-1035 */
+
+ RR_UNKNOWN = 65280 /* Unknown record type RFC-2929 */
+} dns_type_t;
+
+typedef enum edns0_type
+{
+ EDNS0RR_NSID = 3 /* Name Server ID + RFC-5001 */
+} edns0_type_t;
+
+typedef enum dns_class
+{
+ CLASS_IN = 1, /* Internet RFC-1035 */
+ CLASS_CS = 2, /* CSNET (obsolete) RFC-1035 */
+ CLASS_CH = 3, /* CHAOS RFC-1035 */
+ CLASS_HS = 4, /* Hesiod RFC-1035 */
+ CLASS_NONE = 254, /* RFC-2136 */
+ CLASS_ANY = 255, /* All classes RFC-1035 */
+ CLASS_UNKNOWN = 65280 /* Unknown class RFC-2929 */
+} dns_class_t;
+
+typedef enum dns_op
+{
+ OP_QUERY = 0, /* RFC-1035 */
+ OP_IQUERY = 1, /* RFC-1035 RFC-3425 */ /* Obsolete */
+ OP_STATUS = 2, /* RFC-1035 */
+ OP_NOTIFY = 4, /* RFC-1996 */
+ OP_UPDATE = 5, /* RFC-2136 */
+ OP_UNKNOWN = 1 /* Since OP_IQUERY is obsolete */
+} dns_op_t;
+
+typedef enum dns_rcode
+{
+ RCODE_OKAY = 0, /* RFC-1035 */
+ RCODE_FORMAT_ERROR = 1, /* RFC-1035 */
+ RCODE_SERVER_FAILURE = 2, /* RFC-1035 */
+ RCODE_NAME_ERROR = 3, /* RFC-1035 */
+ RCODE_NOT_IMPLEMENTED = 4, /* RFC-1035 */
+ RCODE_REFUSED = 5, /* RFC-1035 */
+ RCODE_YXDOMAIN = 6, /* RFC-2136 */
+ RCODE_YXRRSET = 7, /* RFC-2136 */
+ RCODE_NXRRSET = 8, /* RFC-2136 */
+ RCODE_NOTAUTH = 9, /* RFC-2136 */
+ RCODE_NOTZONE = 10, /* RFC-2136 */
+ RCODE_BADVERS = 16, /* RFC-2671 */
+ RCODE_BADSIG = 16, /* RFC-2845 */
+ RCODE_BADKEY = 17, /* RFC-2845 */
+ RCODE_BADTIME = 18, /* RFC-2845 */
+ RCODE_BADMODE = 19, /* RFC-2845 */
+ RCODE_BADNAME = 20, /* RFC-2930 */
+ RCODE_BADALG = 21, /* RFC-2930 */
+ RCODE_BADTRUC = 22, /* RFC-4635 */
+ RCODE_PRIVATE = 3841, /* RFC-2929 */
+
+ RCODE_NO_MEMORY
+} dns_rcode_t;
+
+typedef enum edns0_label
+{
+ EDNS0_ELT = 0x01, /* RFC-2673 (experimental RFC-3363) */
+ EDNS0_RSVP = 0x3F /* RFC-2671 */
+} edns0_label_t;
+
+typedef uint32_t TTL;
+
+typedef struct dns_question_t /* RFC-1035 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+} dns_question_t;
+
+typedef struct dns_generic_t /* RFC-1035 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+} dns_generic_t;
+
+typedef struct dns_a_t /* RFC-1035 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ in_addr_t address;
+} dns_a_t;
+
+typedef struct dns_ns_t /* RFC-1035 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ const char *nsdname;
+} dns_ns_t;
+
+typedef struct dns_md_t /* RFC-1035 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ const char *madname;
+} dns_md_t;
+
+typedef struct dns_mf_t /* RFC-1035 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ const char *madname;
+} dns_mf_t;
+
+typedef struct dns_cname_t /* RFC-1035 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ const char *cname;
+} dns_cname_t;
+
+typedef struct dns_soa_t /* RFC-1035 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ const char *mname;
+ const char *rname;
+ uint32_t serial;
+ uint32_t refresh;
+ uint32_t retry;
+ uint32_t expire;
+ uint32_t minimum;
+} dns_soa_t;
+
+typedef struct dns_mb_t /* RFC-1035 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ const char *madname;
+} dns_mb_t;
+
+typedef struct dns_mg_t /* RFC-1035 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ const char *mgmname;
+} dns_mg_t;
+
+typedef struct dns_mr_t /* RFC-1035 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ const char *newname;
+} dns_mr_t;
+
+typedef struct dns_null_t /* RFC-1035 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ size_t size;
+ uint8_t *data;
+} dns_null_t;
+
+typedef struct dns_wks_t /* RFC-1035 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ in_addr_t address;
+ int protocol;
+ size_t numbits;
+ uint8_t *bits;
+} dns_wks_t;
+
+typedef struct dns_ptr_t /* RFC-1035 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ const char *ptr;
+} dns_ptr_t;
+
+typedef struct dns_hinfo_t /* RFC-1035 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ const char *cpu;
+ const char *os;
+} dns_hinfo_t;
+
+typedef struct dns_minfo_t /* RFC-1035 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ const char *rmailbx;
+ const char *emailbx;
+} dns_minfo_t;
+
+typedef struct dns_mx_t /* RFC-1035 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ int preference;
+ const char *exchange;
+} dns_mx_t;
+
+typedef struct dns_txt_t /* RFC-1035 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ size_t len;
+ const char *text;
+} dns_txt_t;
+
+typedef struct dns_rp_t /* RFC-1183 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ const char *mbox;
+ const char *domain;
+} dns_rp_t;
+
+typedef struct dns_afsdb_t /* RFC-1183 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ int subtype;
+ const char *hostname;
+} dns_afsdb_t;
+
+typedef struct dns_x25_t /* RFC-1183 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ size_t size;
+ const char *psdnaddress;
+} dns_x25_t;
+
+typedef struct dns_isdn_t /* RFC-1183 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ const char *isdnaddress;
+ const char *sa;
+} dns_isdn_t;
+
+typedef struct dns_rt_t /* RFC-1183 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ int preference;
+ const char *host;
+} dns_rt_t;
+
+typedef struct dns_nsap_t /* RFC-1348 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ const char *length;
+ const char *nsapaddress;
+} dns_nsap_t;
+
+typedef struct dns_nsap_ptr_t /* RFC-1348 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ const char *owner;
+} dns_nsap_ptr_t;
+
+typedef enum dnskey_algorithm /* RFC-2065 */
+{
+ DNSKEYA_RSAMD5 = 1,
+ DNSKEYA_DH = 2, /* RFC-2535 */
+ DNSKEYA_DSA = 3, /* RFC-2535 */
+ DNSKEYA_ECC = 4, /* RFC-2535 */
+ DNSKEYA_RSASHA1 = 5, /* RFC-3110 */
+ DNSKEYA_INDIRECT = 252, /* RFC-2535 */
+ DNSKEYA_PRIVATEDNS = 253,
+ DNSKEYA_PRIVATEOID = 254,
+ DNSKEYA_RSVP = 255
+} dnskey_algorithm;
+
+typedef struct dns_sig_t /* RFC-2065 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ dns_type_t covered;
+ dnskey_algorithm algorithm;
+ int labels;
+ TTL originttl;
+ unsigned long sigexpire;
+ unsigned long timesigned;
+ uint16_t keyfootprint;
+ const char *signer;
+ size_t sigsize;
+ uint8_t *signature;
+} dns_sig_t;
+
+typedef enum dnskey_protocol /* RFC-2535 */
+{
+ DNSKEYP_NONE = 0,
+ DNSKEYP_TLS = 1,
+ DNSKEYP_EMAIL = 2,
+ DNSKEYP_DNSSEC = 3,
+ DNSKEYP_IPSEC = 4,
+ DNSKEYP_ALL = 255
+} dnskey_protocol;
+
+typedef union dnskey_key /* RFC-2065 */
+{
+ struct
+ {
+ size_t expsize;
+ uint8_t *exponent;
+ size_t modsize;
+ uint8_t *modulus;
+ } md5;
+
+ struct
+ {
+ size_t size;
+ uint8_t *data;
+ } unknown;
+} dnskey_key;
+
+typedef struct dns_key_t /* RFC-2065 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ struct
+ {
+ bool authentication;
+ bool confidential;
+ bool experimental;
+ bool user;
+ bool zone;
+ bool host;
+ bool ipsec;
+ bool email; /* not in RFC-2535 */
+ } flags;
+ int signatory;
+ dnskey_protocol protocol;
+ dnskey_algorithm algorithm;
+ dnskey_key key;
+} dns_key_t;
+
+typedef struct dns_px_t /* RFC-2163 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ const char *map822;
+ const char *mapx400;
+} dns_px_t;
+
+typedef struct dnsgpos_angle /* RFC-1712 , RFC1876 */
+{
+ int deg;
+ int min;
+ int sec;
+ int frac;
+ bool nw; /* Northern or Western Hemisphere */
+} dnsgpos_angle;
+
+typedef struct dns_gpos_t /* RFC-1712 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ dnsgpos_angle longitude;
+ dnsgpos_angle latitude;
+ double altitude;
+} dns_gpos_t;
+
+typedef struct dns_aaaa_t /* RFC-1886 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ struct in6_addr address;
+} dns_aaaa_t;
+
+typedef struct dns_loc_t /* RFC-1876 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ int version;
+ unsigned long size; /* plese see RFC-1876 for a discussion */
+ unsigned long horiz_pre; /* of these fields */
+ unsigned long vert_pre;
+ dnsgpos_angle latitude;
+ dnsgpos_angle longitude;
+ long altitude;
+} dns_loc_t;
+
+typedef struct dns_nxt_t /* RFC-2065 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ const char *next;
+ size_t numbits;
+ uint8_t *bitmap;
+} dns_nxt_t;
+
+typedef struct dns_eid_t /* (unknown) */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ size_t size;
+ uint8_t *rawdata;
+} dns_eid_t;
+
+typedef struct dns_nimloc_t /* (unknown) */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ size_t size;
+ uint8_t *rawdata;
+} dns_nimloc_t;
+
+typedef struct dns_srv_t /* RFC-2782 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ int priority;
+ int weight;
+ int port;
+ const char *target;
+} dns_srv_t;
+
+typedef struct dns_atm_t /* (unknown) */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ size_t size;
+ uint8_t *rawdata;
+} dns_atm_t;
+
+typedef struct dns_naptr_t /* RFC-2915 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ int order;
+ int preference;
+ const char *flags;
+ const char *services;
+ const char *regexp;
+ const char *replacement;
+} dns_naptr_t;
+
+typedef struct dns_kx_t /* (unknown) */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ size_t size;
+ uint8_t *rawdata;
+} dns_kx_t;
+
+typedef struct dns_cert_t /* (unknown) */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ size_t size;
+ uint8_t *rawdata;
+} dns_cert_t;
+
+typedef struct dns_a6_t /* RFC-2874 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ size_t mask;
+ struct in6_addr address;
+ const char *prefixname;
+} dns_a6_t;
+
+typedef struct dns_dname_t /* RFC-2672 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ size_t size;
+ uint8_t *rawdata;
+} dns_dname_t;
+
+typedef struct dns_sink_t /* (unknown) */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ size_t size;
+ uint8_t *rawdata;
+} dns_sink_t;
+
+typedef struct edns0_opt_t /* RFC-2671 */
+{
+ edns0_type_t code; /* 0 <= code <= UINT16_MAX */
+ size_t len; /* 0 <= len <= UINT16_MAX */
+ uint8_t *data; /* encoded per RFC specification */
+} edns0_opt_t;
+
+typedef struct dns_edns0opt_t /* RFC-2671 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class; /* not applicable --- set to CLASS_UNKNOWN */
+ TTL ttl; /* not applicable --- set to 0 */
+ size_t udp_payload;
+ int version;
+ bool fdo; /* RFC-3225 */
+ size_t numopts;
+ edns0_opt_t *opts;
+} dns_edns0opt_t;
+
+typedef struct dnsapl_record /* RFC-3123 */
+{
+ int addressfamily;
+ int prefix;
+ size_t afdlength;
+ uint8_t *afdpart;
+ bool negate;
+} dnsapl_record;
+
+typedef struct dns_apl_t /* RFC-3123 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ size_t numrecs;
+ dnsapl_record *recs;
+} dns_apl_t;
+
+
+typedef enum dnsds_digest /* RFC-3658 */
+{
+ DNSDS_SHA1 = 1
+} dnsds_digest;
+
+typedef struct dns_ds_t /* RFC-3658 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ dnskey_protocol keytag;
+ dnskey_algorithm algorithm;
+ dnsds_digest digest;
+ size_t digestlen;
+ uint8_t *digestdata;
+} dns_ds_t;
+
+typedef struct dns_rrsig_t /* RFC-4034 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ dns_type_t covered;
+ dnskey_algorithm algorithm;
+ int labels;
+ TTL originttl;
+ unsigned long sigexpire;
+ unsigned long timesigned;
+ uint16_t keyfootprint;
+ const char *signer;
+ size_t sigsize;
+ uint8_t *signature;
+} dns_rrsig_t;
+
+typedef struct dns_nsec_t /* RFC-4034 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ const char *next;
+ size_t numbits;
+ uint8_t *bitmap;
+} dns_nsec_t;
+
+typedef struct dns_dnskey_t /* RFC-4034 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ bool zonekey;
+ bool sep;
+ dnskey_protocol protocol; /* must be DNSKEYP_DNSSEC */
+ dnskey_algorithm algorithm;
+ size_t keysize;
+ uint8_t *key;
+} dns_dnskey_t;
+
+typedef struct dns_sshfp_t /* RFC-4255 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ dnskey_algorithm algorithm;
+ dnsds_digest fptype;
+ size_t fpsize;
+ uint8_t *fingerprint;
+} dns_sshfp_t;
+
+typedef struct dns_spf_t /* RFC-4408 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ size_t len;
+ const char *text;
+} dns_spf_t;
+
+typedef struct dns_tsig_t /* RFC-2845 */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl; /* must be 0 */
+ const char *algorithm;
+ uint64_t timesigned;
+ unsigned int fudge;
+ size_t MACsize;
+ uint8_t *MAC;
+ int id;
+ int error;
+ size_t lenother;
+ uint8_t *other;
+} dns_tsig_t;
+
+typedef struct dns_x_t /* CATCH-ALL */
+{
+ const char *name;
+ dns_type_t type;
+ dns_class_t class;
+ TTL ttl;
+ size_t size;
+ uint8_t *rawdata;
+} dns_x_t;
+
+typedef union dns_answer_t
+{
+ dns_generic_t generic;
+ dns_x_t x;
+ dns_a_t a;
+ dns_ns_t ns;
+ dns_md_t md;
+ dns_mf_t mf;
+ dns_cname_t cname;
+ dns_soa_t soa;
+ dns_mb_t mb;
+ dns_mg_t mg;
+ dns_mr_t mr;
+ dns_null_t null;
+ dns_wks_t wks;
+ dns_ptr_t ptr;
+ dns_hinfo_t hinfo;
+ dns_minfo_t minfo;
+ dns_mx_t mx;
+ dns_txt_t txt;
+ dns_rp_t rp;
+ dns_afsdb_t afsdb;
+ dns_x25_t x25;
+ dns_isdn_t isdn;
+ dns_rt_t rt;
+ dns_nsap_t nsap;
+ dns_nsap_ptr_t nsap_ptr;
+ dns_sig_t sig;
+ dns_key_t key;
+ dns_px_t px;
+ dns_gpos_t gpos;
+ dns_aaaa_t aaaa;
+ dns_loc_t loc;
+ dns_nxt_t nxt;
+ dns_eid_t eid;
+ dns_nimloc_t nimloc;
+ dns_srv_t srv;
+ dns_atm_t atm;
+ dns_naptr_t naptr;
+ dns_kx_t kx;
+ dns_cert_t cert;
+ dns_a6_t a6;
+ dns_dname_t dname;
+ dns_sink_t sink;
+ dns_edns0opt_t opt;
+ dns_apl_t apl;
+ dns_ds_t ds;
+ dns_rrsig_t rrsig;
+ dns_nsec_t nsec;
+ dns_dnskey_t dnskey;
+ dns_spf_t spf;
+ dns_tsig_t tsig;
+} dns_answer_t;
+
+typedef struct dns_query_t /* RFC-1035 */
+{
+ int id;
+ bool query;
+ dns_op_t opcode;
+ bool aa;
+ bool tc;
+ bool rd;
+ bool ra;
+ bool ad; /* RFC-2065 */
+ bool cd; /* RFC-2065 */
+ dns_rcode_t rcode;
+ size_t qdcount;
+ size_t ancount;
+ size_t nscount;
+ size_t arcount;
+ dns_question_t *questions;
+ dns_answer_t *answers;
+ dns_answer_t *nameservers;
+ dns_answer_t *additional;
+} dns_query_t;
+
+/**********************************************************************/
+
+dns_rcode_t dns_encode(
+ dns_packet_t *const restrict,
+ size_t *const restrict,
+ const dns_query_t *const restrict
+ ) __attribute__ ((nothrow,nonnull));
+
+dns_rcode_t dns_decode(
+ dns_decoded_t *const restrict,
+ size_t *const restrict,
+ const dns_packet_t *const restrict,
+ const size_t
+ ) __attribute__ ((nothrow,nonnull(1,2,3)));
+
+#ifdef __cplusplus
+ }
+# undef class
+# undef restrict
+#endif
+#endif
diff -r 3bd5c2e9e8ac -r fee6b517c6d4 contrib/spcdns/src/luadns.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/spcdns/src/luadns.c Wed Sep 19 15:25:04 2012 +0300
@@ -0,0 +1,768 @@
+/*************************************************************************
+*
+* Copyright 2010 by Sean Conner. All Rights Reserved.
+*
+* 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 3 of the License, or (at your
+* option) any later version.
+*
+* This library is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+* License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with this library; if not, see <http://www.gnu.org/licenses/>.
+*
+**************************************************************************/
+
+/**********************************************************************
+*
+* Implements Lua bindings for my DNS library. This exports four functions
+* in the org.conman.dns object:
+*
+* encode(t)
+*
+* Accepts a table in the form:
+*
+* {
+* id = some_number,
+* query = true, -- making a query
+* rd = true, -- for recursive queries
+* opcode = 'query',
+* question = {
+* name = 'www.example.com',
+* type = 'loc',
+* class = 'in'
+* }, -- and optionally
+* additional = {
+* name = '.',
+* type = 'opt',
+* udp_payload = 1464,
+* version = 0,
+* fdo = false,
+* opts = {
+* {
+* type = 'nsid', -- or a number
+* data = "..."
+* } -- and more, if required
+* }
+* }
+* }
+*
+* And returns a binary string that is the wire format of the
+* query. This binary string can then be sent over a UDP or
+* TCP packet to a DNS server.
+*
+* This returns a binary string on success, nil,rcode on
+* failre.
+*
+* See lua/test.lua for an example of using this function.
+*
+* decode(bs)
+*
+* Decodes a binary string into a table (similar to the table
+* above) for easy use of the DNS response.
+*
+* This returns a table on success, or nil,rcode on failure.
+*
+* See lua/test.lua for an example of using this function.
+*
+* query(server,bs)
+*
+* Sends the encoded binary string to the given server. The
+* server variable is a string of the IP address (IPv4 or
+* IPv6)---hostnames will fail.
+*
+* This function is very stupid simple; it sends the request,
+* and if it doesn't see a reply in 15 seconds, it returns a
+* failure. No restransmission of the packet is done. This is
+* probably fine for simple applications but not for anything
+* heavy duty or rubust.
+*
+* This returns a binary string of the reponse, or nil,rcode on
+* failure.
+*
+* strerror(rcode)
+*
+* Returns a string representation of the server response, or
+* the return value from a failed query() call. This function
+* does not fail (if it does, there's more to worry about).
+*
+*
+* This code is written to C99.
+*
+***************************************************************************/
+
+#include <string.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <arpa/inet.h>
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
+#include "dns.h"
+#include "mappings.h"
+#include "netsimple.h"
+
+/********************************************************************/
+
+static bool parse_edns0_opt(lua_State *L,edns0_opt_t *opt)
+{
+ const char *type;
+ size_t size;
+ bool rc;
+
+ rc = true;
+
+ lua_getfield(L,-1,"data");
+ opt->len = 0;
+ opt->data = (uint8_t *)lua_tolstring(L,-1,&opt->len);
+ lua_pop(L,1);
+
+ lua_getfield(L,-1,"code");
+ if (lua_isnumber(L,-1))
+ opt->code = lua_tointeger(L,-1);
+ else if (lua_isstring(L,-1))
+ {
+ type = lua_tolstring(L,-1,&size);
+
+ if ((memcmp(type,"nsid",size) == 0) || (memcmp(type,"NSID",size) == 0))
+ opt->code = EDNS0RR_NSID;
+ else
+ rc = false;
+ }
+ else
+ rc = false;
+ lua_pop(L,1);
+
+ return rc;
+}
+
+/********************************************************************/
+
+static int dnslua_encode(lua_State *L)
+{
+ dns_question_t domain;
+ dns_query_t query;
+ dns_packet_t buffer[DNS_BUFFER_UDP];
+ size_t len;
+ int qidx;
+ int rc;
+
+ if (!lua_istable(L,1))
+ luaL_typerror(L,1,lua_typename(L,LUA_TTABLE));
+
+ memset(&domain,0,sizeof(domain));
+ memset(&query, 0,sizeof(query));
+
+ lua_getfield(L,1,"question");
+
+ /*----------------------------------------------------------------------
+ ; the user could have passed in multiple parameters; this way, we know
+ ; where the table we just referenced got stashed on the stack.
+ ;---------------------------------------------------------------------*/
+
+ qidx = lua_gettop(L);
+
+ /*-----------------------------------------------------------------
+ ; process the question
+ ;----------------------------------------------------------------*/
+
+ if (!lua_istable(L,qidx))
+ luaL_typerror(L,qidx,lua_typename(L,LUA_TTABLE));
+
+ lua_getfield(L,qidx,"name");
+ lua_getfield(L,qidx,"type");
+ lua_getfield(L,qidx,"class");
+
+ domain.name = luaL_checkstring(L,-3);
+ domain.type = dns_type_value (luaL_optstring(L,-2,"A"));
+ domain.class = dns_class_value(luaL_optstring(L,-1,"IN"));
+
+ lua_pop(L,4);
+
+ lua_getfield(L,1,"id");
+ lua_getfield(L,1,"query");
+ lua_getfield(L,1,"rd");
+ lua_getfield(L,1,"opcode");
+
+ query.id = luaL_optint(L,-4,1234);
+ query.query = lua_toboolean(L,-3);
+ query.rd = lua_toboolean(L,-2);
+ query.opcode = dns_op_value(luaL_optstring(L,-1,"QUERY"));
+ query.qdcount = 1;
+ query.questions = &domain;
+
+ lua_pop(L,4);
+
+ /*----------------------------------------------------------------
+ ; OPT RR support---gring grind grind
+ ;-----------------------------------------------------------------*/
+
+ lua_getfield(L,1,"additional");
+ if (lua_isnil(L,-1))
+ {
+ len = sizeof(buffer);
+ rc = dns_encode(buffer,&len,&query);
+ }
+ else
+ {
+ dns_answer_t edns;
+
+ qidx = lua_gettop(L);
+ if (!lua_istable(L,qidx))
+ luaL_typerror(L,qidx,lua_typename(L,LUA_TTABLE));
+
+ query.arcount = 1;
+ query.additional = &edns;
+
+ memset(&edns,0,sizeof(edns));
+
+ lua_getfield(L,qidx,"name");
+ lua_getfield(L,qidx,"type");
+ lua_getfield(L,qidx,"udp_payload");
+ lua_getfield(L,qidx,"version");
+ lua_getfield(L,qidx,"fdo");
+
+ edns.opt.name = luaL_optstring(L,-5,".");
+ edns.opt.type = dns_type_value(luaL_optstring(L,-4,"OPT"));
+ edns.opt.udp_payload = luaL_optint (L,-3,1464);
+ edns.opt.version = luaL_optint (L,-2,0);
+ edns.opt.fdo = lua_toboolean (L,-1);
+
+ lua_pop(L,5);
+ lua_getfield(L,qidx,"opts");
+
+ if (lua_isnil(L,-1))
+ {
+ edns.opt.numopts = 0;
+ edns.opt.opts = NULL;
+ len = sizeof(buffer);
+ rc = dns_encode(buffer,&len,&query);
+ }
+ else
+ {
+ if (!lua_istable(L,-1))
+ luaL_typerror(L,-1,lua_typename(L,LUA_TTABLE));
+
+ edns.opt.numopts = lua_objlen(L,-1);
+
+ /*----------------------------------------------------------------
+ ; the opts table can either be one record with named fields, or an
+ ; array of records, each with named fields.
+ ;----------------------------------------------------------------*/
+
+ if (edns.opt.numopts == 0)
+ {
+ edns0_opt_t opt;
+
+ if (!parse_edns0_opt(L,&opt))
+ return luaL_error(L,"EDNS0 option not supported");
+
+ edns.opt.opts = &opt;
+ len = sizeof(buffer);
+ rc = dns_encode(buffer,&len,&query);
+ }
+ else
+ {
+ edns0_opt_t opt[edns.opt.numopts];
+
+ for (size_t i = 1 ; i <= edns.opt.numopts ; i++)
+ {
+ lua_pushinteger(L,i);
+ lua_gettable(L,-2);
+
+ if (!lua_istable(L,-1))
+ return luaL_typerror(L,-1,lua_typename(L,LUA_TTABLE));
+
+ if (!parse_edns0_opt(L,&opt[i - 1]))
+ return luaL_error(L,"EDNS0 option no supported");
+
+ lua_pop(L,1);
+ }
+ edns.opt.opts = opt;
+ len = sizeof(buffer);
+ rc = dns_encode(buffer,&len,&query);
+ }
+ }
+ }
+
+ if (rc != RCODE_OKAY)
+ {
+ lua_pushnil(L);
+ lua_pushstring(L,dns_rcode_text(rc));
+ return 2;
+ }
+
+ lua_pushlstring(L,(char *)buffer,len);
+ return 1;
+}
+
+/********************************************************************/
+
+static void push_dnsgpos_angle(lua_State *L,dnsgpos_angle *pa,bool lat)
+{
+ lua_createtable(L,0,4);
+ lua_pushinteger(L,pa->deg);
+ lua_setfield(L,-2,"deg");
+ lua_pushinteger(L,pa->min);
+ lua_setfield(L,-2,"min");
+ lua_pushnumber(L,(double)pa->sec + ((double)pa->frac / 1000.0));
+ lua_setfield(L,-2,"sec");
+ lua_pushboolean(L,pa->nw);
+ lua_setfield(L,-2,"nw");
+ if (lat)
+ lua_pushlstring(L,(pa->nw) ? "N" : "S" , 1);
+ else
+ lua_pushlstring(L,(pa->nw) ? "W" : "E" , 1);
+ lua_setfield(L,-2,"hemisphere");
+}
+
+/********************************************************************/
+
+static void decode_answer(
+ lua_State *L,
+ int tab,
+ const char *name,
+ dns_answer_t *pans,
+ size_t cnt,
+ bool dup
+)
+{
+ char ipaddr[INET6_ADDRSTRLEN];
+
+ lua_createtable(L,cnt,0);
+
+ for (size_t i = 0 ; i < cnt ; i++)
+ {
+ lua_pushinteger(L,i + 1);
+ lua_createtable(L,0,0);
+
+ lua_pushstring(L,pans[i].generic.name);
+ lua_setfield(L,-2,"name");
+ lua_pushinteger(L,pans[i].generic.ttl);
+ lua_setfield(L,-2,"ttl");
+ lua_pushstring(L,dns_class_text(pans[i].generic.class));
+ lua_setfield(L,-2,"class");
+ lua_pushstring(L,dns_type_text(pans[i].generic.type));
+ lua_setfield(L,-2,"type");
+
+ switch(pans[i].generic.type)
+ {
+ case RR_A:
+ inet_ntop(AF_INET,&pans[i].a.address,ipaddr,sizeof(ipaddr));
+ lua_pushstring(L,ipaddr);
+ lua_setfield(L,-2,"address");
+ lua_pushlstring(L,(char *)&pans[i].a.address,4);
+ lua_setfield(L,-2,"raw_address");
+ break;
+
+ case RR_SOA:
+ lua_pushstring(L,pans[i].soa.mname);
+ lua_setfield(L,-2,"mname");
+ lua_pushstring(L,pans[i].soa.rname);
+ lua_setfield(L,-2,"rname");
+ lua_pushnumber(L,pans[i].soa.serial);
+ lua_setfield(L,-2,"serial");
+ lua_pushnumber(L,pans[i].soa.refresh);
+ lua_setfield(L,-2,"refresh");
+ lua_pushnumber(L,pans[i].soa.retry);
+ lua_setfield(L,-2,"retry");
+ lua_pushnumber(L,pans[i].soa.expire);
+ lua_setfield(L,-2,"expire");
+ lua_pushnumber(L,pans[i].soa.minimum);
+ lua_setfield(L,-2,"minimum");
+ break;
+
+ case RR_NAPTR:
+ lua_pushinteger(L,pans[i].naptr.order);
+ lua_setfield(L,-2,"order");
+ lua_pushinteger(L,pans[i].naptr.preference);
+ lua_setfield(L,-2,"preference");
+ lua_pushstring(L,pans[i].naptr.flags);
+ lua_setfield(L,-2,"flags");
+ lua_pushstring(L,pans[i].naptr.services);
+ lua_setfield(L,-2,"services");
+ lua_pushstring(L,pans[i].naptr.regexp);
+ lua_setfield(L,-2,"regexp");
+ lua_pushstring(L,pans[i].naptr.replacement);
+ lua_setfield(L,-2,"replacement");
+ break;
+
+ case RR_AAAA:
+ inet_ntop(AF_INET6,&pans[i].aaaa.address,ipaddr,sizeof(ipaddr));
+ lua_pushstring(L,ipaddr);
+ lua_setfield(L,-2,"address");
+ lua_pushlstring(L,(char *)&pans[i].aaaa.address,16);
+ lua_setfield(L,-2,"raw_address");
+ break;
+
+ case RR_SRV:
+ lua_pushinteger(L,pans[i].srv.priority);
+ lua_setfield(L,-2,"priority");
+ lua_pushinteger(L,pans[i].srv.weight);
+ lua_setfield(L,-2,"weight");
+ lua_pushinteger(L,pans[i].srv.port);
+ lua_setfield(L,-2,"port");
+ lua_pushstring(L,pans[i].srv.target);
+ lua_setfield(L,-2,"target");
+ break;
+
+ case RR_WKS:
+ inet_ntop(AF_INET,&pans[i].wks.address,ipaddr,sizeof(ipaddr));
+ lua_pushstring(L,ipaddr);
+ lua_setfield(L,-2,"address");
+ lua_pushlstring(L,(char *)&pans[i].wks.address,4);
+ lua_setfield(L,-2,"raw_address");
+ lua_pushinteger(L,pans[i].wks.protocol);
+ lua_setfield(L,-2,"protocol");
+ lua_pushlstring(L,(char *)pans[i].wks.bits,pans[i].wks.numbits);
+ lua_setfield(L,-2,"bits");
+ break;
+
+ case RR_GPOS:
+ push_dnsgpos_angle(L,&pans[i].gpos.latitude,true);
+ lua_setfield(L,-2,"longitude");
+ push_dnsgpos_angle(L,&pans[i].gpos.longitude,false);
+ lua_setfield(L,-2,"latitude");
+ lua_pushnumber(L,pans[i].gpos.altitude);
+ lua_setfield(L,-2,"altitude");
+ break;
+
+ case RR_LOC:
+ lua_pushnumber(L,pans[i].loc.size);
+ lua_setfield(L,-2,"size");
+ lua_pushnumber(L,pans[i].loc.horiz_pre);
+ lua_setfield(L,-2,"horiz_pre");
+ lua_pushnumber(L,pans[i].loc.vert_pre);
+ lua_setfield(L,-2,"vert_pre");
+ push_dnsgpos_angle(L,&pans[i].loc.latitude,true);
+ lua_setfield(L,-2,"latitude");
+ push_dnsgpos_angle(L,&pans[i].loc.longitude,false);
+ lua_setfield(L,-2,"longitude");
+ lua_pushnumber(L,pans[i].loc.altitude);
+ lua_setfield(L,-2,"altitude");
+ break;
+
+ case RR_PX:
+ lua_pushstring(L,pans[i].px.map822);
+ lua_setfield(L,-2,"map822");
+ lua_pushstring(L,pans[i].px.mapx400);
+ lua_setfield(L,-2,"mapx400");
+ break;
+
+ case RR_RP:
+ lua_pushstring(L,pans[i].rp.mbox);
+ lua_setfield(L,-2,"mbox");
+ lua_pushstring(L,pans[i].rp.domain);
+ lua_setfield(L,-2,"domain");
+ break;
+
+ case RR_MINFO:
+ lua_pushstring(L,pans[i].minfo.rmailbx);
+ lua_setfield(L,-2,"rmailbx");
+ lua_pushstring(L,pans[i].minfo.emailbx);
+ lua_setfield(L,-2,"emailbx");
+ break;
+
+ case RR_AFSDB:
+ lua_pushinteger(L,pans[i].afsdb.subtype);
+ lua_setfield(L,-2,"subtype");
+ lua_pushstring(L,pans[i].afsdb.hostname);
+ lua_setfield(L,-2,"hostname");
+ break;
+
+ case RR_RT:
+ lua_pushinteger(L,pans[i].rt.preference);
+ lua_setfield(L,-2,"preference");
+ lua_pushstring(L,pans[i].rt.host);
+ lua_setfield(L,-2,"host");
+ break;
+
+ case RR_MX:
+ lua_pushinteger(L,pans[i].mx.preference);
+ lua_setfield(L,-2,"preference");
+ lua_pushstring(L,pans[i].mx.exchange);
+ lua_setfield(L,-2,"exchange");
+ break;
+
+ case RR_NSAP:
+ lua_pushstring(L,pans[i].nsap.length);
+ lua_setfield(L,-2,"length");
+ lua_pushstring(L,pans[i].nsap.nsapaddress);
+ lua_setfield(L,-2,"address");
+ break;
+
+ case RR_ISDN:
+ lua_pushstring(L,pans[i].isdn.isdnaddress);
+ lua_setfield(L,-2,"address");
+ lua_pushstring(L,pans[i].isdn.sa);
+ lua_setfield(L,-2,"sa");
+ break;
+
+ case RR_HINFO:
+ lua_pushstring(L,pans[i].hinfo.cpu);
+ lua_setfield(L,-2,"cpu");
+ lua_pushstring(L,pans[i].hinfo.os);
+ lua_setfield(L,-2,"os");
+ break;
+
+ case RR_X25:
+ lua_pushlstring(L,pans[i].x25.psdnaddress,pans[i].x25.size);
+ lua_setfield(L,-2,"address");
+ break;
+
+ case RR_SPF:
+ lua_pushlstring(L,pans[i].spf.text,pans[i].spf.len);
+ lua_setfield(L,-2,"text");
+ break;
+
+ case RR_TXT:
+ lua_pushlstring(L,pans[i].txt.text,pans[i].txt.len);
+ lua_setfield(L,-2,"text");
+ break;
+
+ case RR_NSAP_PTR:
+ lua_pushstring(L,pans[i].nsap_ptr.owner);
+ lua_setfield(L,-2,"owner");
+ break;
+
+ case RR_MD:
+ lua_pushstring(L,pans[i].md.madname);
+ lua_setfield(L,-2,"madname");
+ break;
+
+ case RR_MF:
+ lua_pushstring(L,pans[i].mf.madname);
+ lua_setfield(L,-2,"madname");
+ break;
+
+ case RR_MB:
+ lua_pushstring(L,pans[i].mb.madname);
+ lua_setfield(L,-2,"madname");
+ break;
+
+ case RR_MG:
+ lua_pushstring(L,pans[i].mg.mgmname);
+ lua_setfield(L,-2,"mgmname");
+ break;
+
+ case RR_MR:
+ lua_pushstring(L,pans[i].mr.newname);
+ lua_setfield(L,-2,"newname");
+ break;
+
+ case RR_NS:
+ lua_pushstring(L,pans[i].ns.nsdname);
+ lua_setfield(L,-2,"nsdname");
+ break;
+
+ case RR_PTR:
+ lua_pushstring(L,pans[i].ptr.ptr);
+ lua_setfield(L,-2,"ptr");
+ break;
+
+ case RR_CNAME:
+ lua_pushstring(L,pans[i].cname.cname);
+ lua_setfield(L,-2,"cname");
+ break;
+
+ case RR_NULL:
+ lua_pushlstring(L,(char *)pans[i].null.data,pans[i].null.size);
+ lua_setfield(L,-2,"data");
+ break;
+
+ case RR_OPT:
+ lua_pushinteger(L,pans[i].opt.udp_payload);
+ lua_setfield(L,-2,"udp_payload");
+ lua_pushinteger(L,pans[i].opt.version);
+ lua_setfield(L,-2,"version");
+ lua_pushboolean(L,pans[i].opt.fdo);
+ lua_setfield(L,-2,"fdo");
+ lua_createtable(L,pans[i].opt.numopts,0);
+ for (size_t j = 0 ; j < pans[i].opt.numopts ; j++)
+ {
+ lua_pushinteger(L,i + 1);
+ lua_createtable(L,0,2);
+ lua_pushlstring(L,(char *)pans[i].opt.opts[j].data,pans[i].opt.opts[j].len);
+ lua_setfield(L,-2,"data");
+ if (pans[i].opt.opts[j].code == EDNS0RR_NSID)
+ lua_pushstring(L,"NSID");
+ else
+ lua_pushinteger(L,pans[i].opt.opts[i].code);
+ lua_setfield(L,-2,"code");
+ lua_settable(L,-3);
+ }
+ lua_setfield(L,-2,"opts");
+ break;
+
+ default:
+ lua_pushlstring(L,(char *)pans[i].x.rawdata,pans[i].x.size);
+ lua_setfield(L,-2,"rawdata");
+ break;
+ }
+
+ if (dup)
+ {
+ lua_getfield(L,-1,"name");
+ lua_pushvalue(L,-2);
+ lua_settable(L,-5);
+ }
+
+ lua_settable(L,-3);
+ }
+
+ lua_setfield(L,tab,name);
+}
+
+/**********************************************************************/
+
+static int dnslua_decode(lua_State *L)
+{
+ dns_decoded_t bufresult[DNS_DECODEBUF_8K];
+ dns_packet_t data [DNS_BUFFER_UDP];
+ const char *luadata;
+ dns_query_t *result;
+ size_t size;
+ int tab;
+ int rc;
+
+ /*---------------------------------------------------------------------
+ ; We need to make sure our data is properly aligned. And hey, this is
+ ; Lua---a scripting lanague. We can afford a bit of waste 8-)
+ ;----------------------------------------------------------------------*/
+
+ luadata = luaL_checklstring(L,1,&size);
+ if (size > MAX_DNS_QUERY_SIZE) size = MAX_DNS_QUERY_SIZE;
+ memcpy(data,luadata,size);
+
+ rc = dns_decode(bufresult,&(size_t){sizeof(bufresult)},data,size);
+
+ if (rc != RCODE_OKAY)
+ {
+ lua_pushnil(L);
+ lua_pushstring(L,dns_rcode_text(rc));
+ return 2;
+ }
+
+ result = (dns_query_t *)bufresult;
+
+ lua_createtable(L,0,0);
+ tab = lua_gettop(L);
+
+ lua_pushboolean(L,result->aa);
+ lua_setfield(L,tab,"aa");
+ lua_pushboolean(L,result->tc);
+ lua_setfield(L,tab,"tc");
+ lua_pushboolean(L,result->rd);
+ lua_setfield(L,tab,"rd");
+ lua_pushboolean(L,result->ra);
+ lua_setfield(L,tab,"ra");
+ lua_pushboolean(L,result->ad);
+ lua_setfield(L,tab,"ad");
+ lua_pushboolean(L,result->cd);
+ lua_setfield(L,tab,"cd");
+ lua_pushinteger(L,result->rcode);
+ lua_setfield(L,tab,"rcode");
+
+ if (result->qdcount)
+ {
+ lua_createtable(L,0,3);
+ lua_pushstring(L,result->questions[0].name);
+ lua_setfield(L,-2,"name");
+ lua_pushstring(L,dns_class_text(result->questions[0].class));
+ lua_setfield(L,-2,"class");
+ lua_pushstring(L,dns_type_text(result->questions[0].type));
+ lua_setfield(L,-2,"type");
+ lua_setfield(L,tab,"question");
+ }
+
+ decode_answer(L,tab,"answers" , result->answers , result->ancount,false);
+ decode_answer(L,tab,"nameservers" , result->nameservers, result->nscount,false);
+ decode_answer(L,tab,"additional" , result->additional , result->arcount,true);
+
+ assert(tab == lua_gettop(L));
+
+ return 1;
+}
+
+/*********************************************************************/
+
+static int dnslua_strerror(lua_State *L)
+{
+ lua_pushstring(L,dns_rcode_text(luaL_checkint(L,1)));
+ return 1;
+}
+
+/*********************************************************************/
+
+static int dnslua_query(lua_State *L)
+{
+ sockaddr_all srvaddr;
+ const char *server;
+ const char *luaquery;
+ size_t querysize;
+ dns_packet_t query[DNS_BUFFER_UDP];
+ dns_packet_t reply[DNS_BUFFER_UDP];
+ size_t replysize;
+ int rc;
+
+ server = luaL_checkstring(L,1);
+ luaquery = luaL_checklstring(L,2,&querysize);
+
+ if (net_server(&srvaddr,server) < 0)
+ luaL_error(L,"%s is not an IPv4/IPv6 address",server);
+
+ if (querysize > MAX_DNS_QUERY_SIZE) querysize = MAX_DNS_QUERY_SIZE;
+ memcpy(query,luaquery,querysize);
+ replysize = sizeof(reply);
+ rc = net_request(&srvaddr,reply,&replysize,query,querysize);
+
+ if (rc != 0)
+ {
+ lua_pushnil(L);
+ lua_pushinteger(L,rc);
+ return 2;
+ }
+
+ lua_pushlstring(L,(char *)reply,replysize);
+ return 1;
+}
+
+/**********************************************************************/
+
+static const struct luaL_reg reg_dns[] =
+{
+ { "encode" , dnslua_encode } ,
+ { "decode" , dnslua_decode } ,
+ { "strerror" , dnslua_strerror } ,
+ { "query" , dnslua_query } ,
+ { NULL , NULL }
+};
+
+int luaopen_org_conman_dns(lua_State *L)
+{
+ luaL_register(L,"org.conman.dns",reg_dns);
+
+ lua_pushliteral(L,"Copyright 2010 by Sean Conner. All Rights Reserved.");
+ lua_setfield(L,-2,"COPYRIGHT");
+
+ lua_pushliteral(L,"Encode/Decode and send queries via DNS");
+ lua_setfield(L,-2,"DESCRIPTION");
+
+ lua_pushliteral(L,"0.0.1");
+ lua_setfield(L,-2,"VERSION");
+
+ return 1;
+}
+
+/**********************************************************************/
+
diff -r 3bd5c2e9e8ac -r fee6b517c6d4 contrib/spcdns/src/mappings.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/spcdns/src/mappings.c Wed Sep 19 15:25:04 2012 +0300
@@ -0,0 +1,373 @@
+/*************************************************************************
+*
+* Copyright 2010 by Sean Conner. All Rights Reserved.
+*
+* 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 3 of the License, or (at your
+* option) any later version.
+*
+* This library is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+* License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with this library; if not, see <http://www.gnu.org/licenses/>.
+*
+**************************************************************************/
+
+/***********************************************************************
+*
+* Implementation of mapping values to strings, or strings to values.
+*
+* This code is written to C99.
+*
+************************************************************************/
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include "dns.h"
+#include "mappings.h"
+
+/************************************************************************
+*
+* The following structure is used to map values to strings. The arrays
+* defined by this structure *MUST* be sorted by value in ascending order.
+*
+*************************************************************************/
+
+struct int_string_map
+{
+ const int value;
+ const char *const text;
+};
+
+/*******************************************************************
+*
+* The following structure is used to map strings to values. The arrays
+* defined by this structure *MUST* be sorted by the strings in ascending
+* order.
+*
+*********************************************************************/
+
+struct string_int_map
+{
+ const char *const text;
+ const int value;
+};
+
+/************************************************************************/
+
+static const struct int_string_map cm_dns_rcode[] =
+{
+ { RCODE_OKAY , "No error" } ,
+ { RCODE_FORMAT_ERROR , "Format error" } ,
+ { RCODE_SERVER_FAILURE , "Server failure" } ,
+ { RCODE_NAME_ERROR , "Non-existant domain" } ,
+ { RCODE_NOT_IMPLEMENTED , "Not implemented" } ,
+ { RCODE_REFUSED , "Query refused" } ,
+ { RCODE_YXDOMAIN , "Name exists when it should not" } ,
+ { RCODE_YXRRSET , "RRset exists when it should not" } ,
+ { RCODE_NXRRSET , "RRset does not exist" } ,
+ { RCODE_NOTAUTH , "Server not authoritative" } ,
+ { RCODE_NOTZONE , "Zone not in zone section" } ,
+ { RCODE_BADVERS , "Bad OPT version/TSIG failed" } ,
+ { RCODE_BADKEY , "Key not recognized" } ,
+ { RCODE_BADTIME , "Signature out of time window" } ,
+ { RCODE_BADMODE , "Bad TKEY mode" } ,
+ { RCODE_BADNAME , "Duplicate key name" } ,
+ { RCODE_BADALG , "Algorithm not supported" } ,
+ { RCODE_BADTRUC , "Bad truncation" } ,
+ { RCODE_NO_MEMORY , "No memory" } ,
+};
+
+#define RCODE_COUNT (sizeof(cm_dns_rcode) / sizeof(struct int_string_map))
+
+static const struct int_string_map cm_dns_type[] =
+{
+ { RR_A , "A" } ,
+ { RR_NS , "NS" } ,
+ { RR_MD , "MD" } ,
+ { RR_MF , "MF" } ,
+ { RR_CNAME , "CNAME" } ,
+ { RR_SOA , "SOA" } ,
+ { RR_MB , "MB" } ,
+ { RR_MG , "MG" } ,
+ { RR_MR , "MR" } ,
+ { RR_NULL , "NULL" } ,
+ { RR_WKS , "WKS" } ,
+ { RR_PTR , "PTR" } ,
+ { RR_HINFO , "HINFO" } ,
+ { RR_MINFO , "MINFO" } ,
+ { RR_MX , "MX" } ,
+ { RR_TXT , "TXT" } ,
+ { RR_RP , "RP" } ,
+ { RR_AFSDB , "AFSDB" } ,
+ { RR_X25 , "X25" } ,
+ { RR_ISDN , "ISDN" } ,
+ { RR_RT , "RT" } ,
+ { RR_NSAP , "NSAP" } ,
+ { RR_NSAP_PTR , "NSAP-PTR" } ,
+ { RR_SIG , "SIG" } ,
+ { RR_KEY , "KEY" } ,
+ { RR_PX , "PX" } ,
+ { RR_GPOS , "GPOS" } ,
+ { RR_AAAA , "AAAA" } ,
+ { RR_LOC , "LOC" } ,
+ { RR_NXT , "NXT" } ,
+ { RR_EID , "EID" } ,
+ { RR_NIMLOC , "NIMLOC" } ,
+ { RR_SRV , "SRV" } ,
+ { RR_ATM , "ATM" } ,
+ { RR_NAPTR , "NAPTR" } ,
+ { RR_KX , "KX" } ,
+ { RR_CERT , "CERT" } ,
+ { RR_A6 , "A6" } ,
+ { RR_DNAME , "DNAME" } ,
+ { RR_SINK , "SINK" } ,
+ { RR_OPT , "OPT" } ,
+ { RR_APL , "APL" } ,
+ { RR_DS , "DS" } ,
+ { RR_RRSIG , "RRSIG" } ,
+ { RR_NSEC , "NSEC" } ,
+ { RR_DNSKEY , "DNSKEY" } ,
+ { RR_SPF , "SPF" } ,
+ { RR_TSIG , "TSIG" } ,
+ { RR_IXFR , "IXFR" } ,
+ { RR_AXFR , "AXFR" } ,
+ { RR_MAILB , "MAILB" } ,
+ { RR_MAILA , "MAILA" } ,
+ { RR_ANY , "ANY" }
+};
+
+#define TYPE_COUNT (sizeof(cm_dns_type) / sizeof(struct int_string_map))
+
+static const struct string_int_map cm_dns_type_is[] =
+{
+ { "A" , RR_A } ,
+ { "A6" , RR_A6 } ,
+ { "AAAA" , RR_AAAA } ,
+ { "AFSDB" , RR_AFSDB } ,
+ { "ANY" , RR_ANY } ,
+ { "APL" , RR_APL } ,
+ { "ATM" , RR_ATM } ,
+ { "AXFR" , RR_AXFR } ,
+ { "CERT" , RR_CERT } ,
+ { "CNAME" , RR_CNAME } ,
+ { "DNAME" , RR_DNAME } ,
+ { "DNSKEY" , RR_DNSKEY } ,
+ { "DS" , RR_DS } ,
+ { "EID" , RR_EID } ,
+ { "GPOS" , RR_GPOS } ,
+ { "HINFO" , RR_HINFO } ,
+ { "ISDN" , RR_ISDN } ,
+ { "IXFR" , RR_IXFR } ,
+ { "KEY" , RR_KEY } ,
+ { "KX" , RR_KX } ,
+ { "LOC" , RR_LOC } ,
+ { "MAILA" , RR_MAILA } ,
+ { "MAILB" , RR_MAILB } ,
+ { "MB" , RR_MB } ,
+ { "MD" , RR_MD } ,
+ { "MF" , RR_MF } ,
+ { "MG" , RR_MG } ,
+ { "MINFO" , RR_MINFO } ,
+ { "MR" , RR_MR } ,
+ { "MX" , RR_MX } ,
+ { "NAPTR" , RR_NAPTR } ,
+ { "NIMLOC" , RR_NIMLOC } ,
+ { "NS" , RR_NS } ,
+ { "NSAP" , RR_NSAP } ,
+ { "NSAP-PTR" , RR_NSAP_PTR } ,
+ { "NSEC" , RR_NSEC } ,
+ { "NULL" , RR_NULL } ,
+ { "NXT" , RR_NXT } ,
+ { "OPT" , RR_OPT } ,
+ { "PTR" , RR_PTR } ,
+ { "PX" , RR_PX } ,
+ { "RP" , RR_RP } ,
+ { "RRSIG" , RR_RRSIG } ,
+ { "RT" , RR_RT } ,
+ { "SIG" , RR_SIG } ,
+ { "SINK" , RR_SINK } ,
+ { "SOA" , RR_SOA } ,
+ { "SPF" , RR_SPF } ,
+ { "SRV" , RR_SRV } ,
+ { "TSIG" , RR_TSIG } ,
+ { "TXT" , RR_TXT } ,
+ { "WKS" , RR_WKS } ,
+ { "X25" , RR_X25 } ,
+};
+
+static const struct int_string_map cm_dns_class[] =
+{
+ { CLASS_IN , "IN" } ,
+ { CLASS_CS , "CS" } ,
+ { CLASS_CH , "CH" } ,
+ { CLASS_HS , "HS" } ,
+ { CLASS_NONE , "NONE" }
+};
+
+#define CLASS_COUNT (sizeof(cm_dns_class) / sizeof(struct int_string_map))
+
+static const struct string_int_map cm_dns_class_is[] =
+{
+ { "CH" , CLASS_CH } ,
+ { "CS" , CLASS_CS } ,
+ { "HS" , CLASS_HS } ,
+ { "IN" , CLASS_IN } ,
+ { "NONE" , CLASS_NONE } ,
+};
+
+static const struct int_string_map cm_dns_op[] =
+{
+ { OP_QUERY , "QUERY" } ,
+ { OP_IQUERY , "IQUERY" } ,
+ { OP_STATUS , "STATUS" } ,
+ { OP_NOTIFY , "NOTIFY" } ,
+ { OP_UPDATE , "UPDATE" }
+};
+
+#define OP_COUNT (sizeof(cm_dns_op) / sizeof(struct int_string_map))
+
+static const struct string_int_map cm_dns_op_is[] =
+{
+ { "IQUERY" , OP_IQUERY } ,
+ { "NOTIFY" , OP_NOTIFY } ,
+ { "QUERY" , OP_QUERY } ,
+ { "STATUS" , OP_STATUS } ,
+ { "UPDATE" , OP_UPDATE }
+};
+
+/*************************************************************************/
+
+static int intstr_cmp(const void *needle,const void *haystack)
+{
+ const struct int_string_map *pism = haystack;
+ const int *pi = needle;
+
+ assert(needle != NULL);
+ assert(haystack != NULL);
+
+ return *pi - pism->value;
+}
+
+/*********************************************************************/
+
+static int strint_cmp(const void *needle,const void *haystack)
+{
+ const struct string_int_map *psim = haystack;
+ const char *key = needle;
+
+ assert(needle != NULL);
+ assert(haystack != NULL);
+
+ return strcmp(key,psim->text);
+}
+
+/**********************************************************************/
+
+static const char *itosdef(
+ int v,
+ const struct int_string_map *const restrict pitab,
+ const size_t itabcnt,
+ const char *const restrict def
+)
+{
+ struct int_string_map *pism;
+
+ assert(v >= 0);
+ assert(pitab != NULL);
+ assert(itabcnt > 0);
+ assert(def != NULL);
+
+ pism = bsearch(&v,pitab,itabcnt,sizeof(struct int_string_map),intstr_cmp);
+ if (pism)
+ return pism->text;
+ else
+ return def;
+}
+
+/********************************************************************/
+
+static int stoidef(
+ const char *const restrict tag,
+ const struct string_int_map *const restrict pstab,
+ const size_t stabcnt,
+ const int def
+)
+{
+ struct string_int_map *psim;
+ size_t len = strlen(tag) + 1;
+ char buffer[len];
+
+ for (size_t i = 0 ; i < len ; i++)
+ buffer[i] = toupper(tag[i]);
+
+ psim = bsearch(buffer,pstab,stabcnt,sizeof(struct string_int_map),strint_cmp);
+ if (psim)
+ return psim->value;
+ else
+ return def;
+}
+
+/*******************************************************************/
+
+const char *dns_rcode_text(const dns_rcode_t r)
+{
+ return itosdef(r,cm_dns_rcode,RCODE_COUNT,"Unknown error");
+}
+
+/*********************************************************************/
+
+const char *dns_type_text(const dns_type_t t)
+{
+ return itosdef(t,cm_dns_type,TYPE_COUNT,"X-UNKN");
+}
+
+/**********************************************************************/
+
+const char *dns_class_text(const dns_class_t c)
+{
+ return itosdef(c,cm_dns_class,CLASS_COUNT,"X-UNKN");
+}
+
+/*******************************************************************/
+
+const char *dns_op_text(const dns_op_t o)
+{
+ return itosdef(o,cm_dns_op,OP_COUNT,"X-UNKNOWN");
+}
+
+/********************************************************************/
+
+dns_type_t dns_type_value(const char *tag)
+{
+ return stoidef(tag,cm_dns_type_is,TYPE_COUNT,RR_UNKNOWN);
+}
+
+/*********************************************************************/
+
+dns_class_t dns_class_value(const char *tag)
+{
+ return stoidef(tag,cm_dns_class_is,CLASS_COUNT,CLASS_UNKNOWN);
+}
+
+/**********************************************************************/
+
+dns_op_t dns_op_value(const char *tag)
+{
+ return stoidef(tag,cm_dns_op_is,OP_COUNT,OP_UNKNOWN);
+}
+
+/**********************************************************************/
diff -r 3bd5c2e9e8ac -r fee6b517c6d4 contrib/spcdns/src/mappings.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/spcdns/src/mappings.h Wed Sep 19 15:25:04 2012 +0300
@@ -0,0 +1,55 @@
+/*************************************************************************
+*
+* Copyright 2010 by Sean Conner. All Rights Reserved.
+*
+* 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 3 of the License, or (at your
+* option) any later version.
+*
+* This library is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+* License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with this library; if not, see <http://www.gnu.org/licenses/>.
+*
+**************************************************************************/
+
+/**************************************************************************
+*
+* Useful routines to convert error codes, RR, Class and Opcode values into
+* strings, and strings into their equivilent RR, Class or Opcode values.
+*
+* This file assumes C99. You must include the following files before
+* including this one:
+*
+* #include "dns.h"
+*
+**************************************************************************/
+
+#ifndef DNS_MAPPINGS_H
+#define DNS_MAPPINGS_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#ifndef __GNUC__
+# define __attribute__(x)
+#endif
+
+const char *dns_rcode_text (const dns_rcode_t) __attribute__ ((pure,nothrow));
+const char *dns_type_text (const dns_type_t) __attribute__ ((pure,nothrow));
+const char *dns_class_text (const dns_class_t) __attribute__ ((pure,nothrow));
+const char *dns_op_text (const dns_op_t) __attribute__ ((pure,nothrow));
+
+dns_type_t dns_type_value (const char *const) __attribute__ ((pure,nothrow,nonnull));
+dns_class_t dns_class_value (const char *const) __attribute__ ((pure,nothrow,nonnull));
+dns_op_t dns_op_value (const char *const) __attribute__ ((pure,nothrow,nonnull));
+
+#ifdef __cplusplus
+ }
+#endif
+#endif
diff -r 3bd5c2e9e8ac -r fee6b517c6d4 contrib/spcdns/src/netsimple.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/spcdns/src/netsimple.c Wed Sep 19 15:25:04 2012 +0300
@@ -0,0 +1,156 @@
+/*************************************************************************
+*
+* Copyright 2010 by Sean Conner. All Rights Reserved.
+*
+* 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 3 of the License, or (at your
+* option) any later version.
+*
+* This library is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+* License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with this library; if not, see <http://www.gnu.org/licenses/>.
+*
+**************************************************************************/
+
+/*********************************************************************
+*
+* Implementation of the simple network interface for DNS queries. Two
+* functions are exported:
+*
+* net_server()
+*
+* decode the IP address (IPv4/IPv6) from a text representation
+* to a network format.
+*
+* net_request()
+*
+* Send a request to the given server and wait a reponse. This
+* function is stupid simple---it opens a socket, sends the
+* request via sendto(), waits for up to 15 seconds for a
+* reply. If no reply is seen in 15 seconds, close the socket
+* and return an error---otherwise, call recvfrom(), close the
+* socket and return the data.
+*
+* Like I said, stupid simple. It's enough for testing and
+* very simple programs.
+*
+* This code is written for C99.
+*
+**************************************************************************/
+
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <assert.h>
+
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <poll.h>
+#include <unistd.h>
+
+#include "dns.h"
+#include "netsimple.h"
+
+/************************************************************************/
+
+int net_server(
+ sockaddr_all *const restrict addr,
+ const char *const restrict host
+)
+{
+ assert(addr != NULL);
+ assert(host != NULL);
+
+ memset(addr,0,sizeof(sockaddr_all));
+
+ if (inet_pton(AF_INET,host,&addr->sin.sin_addr.s_addr) < 0)
+ {
+ if (inet_pton(AF_INET6,host,&addr->sin6.sin6_addr.s6_addr) < 0)
+ return errno;
+ addr->sin6.sin6_family = AF_INET6;
+ addr->sin6.sin6_port = htons(53);
+ }
+ else
+ {
+ addr->sin.sin_family = AF_INET;
+ addr->sin.sin_port = htons(53);
+ }
+
+ return 0;
+}
+
+/************************************************************************/
+
+int net_request(
+ sockaddr_all *const restrict srvaddr,
+ dns_packet_t *const restrict dest,
+ size_t *const restrict dsize,
+ const dns_packet_t *const restrict src,
+ const size_t ssize
+)
+{
+ struct pollfd polldat;
+ socklen_t asize;
+ ssize_t bytes;
+ int sock;
+ int rc;
+ int err;
+
+ switch(srvaddr->sa.sa_family)
+ {
+ case AF_INET: asize = sizeof(struct sockaddr_in); break;
+ case AF_INET6: asize = sizeof(struct sockaddr_in6); break;
+ default: assert(0); return EPROTOTYPE;
+ }
+
+ sock = socket(srvaddr->sa.sa_family,SOCK_DGRAM,0);
+ if (sock < 0)
+ return errno;
+
+ bytes = sendto(sock,src,ssize,0,&srvaddr->sa,asize);
+ if (bytes < 0)
+ {
+ err = errno;
+ close(sock);
+ return err;
+ }
+
+ polldat.fd = sock;
+ polldat.events = POLLIN;
+
+ rc = poll(&polldat,1,15000);
+ if (rc < 0)
+ {
+ err = errno;
+ close(sock);
+ return errno;
+ }
+
+ if (rc == 0)
+ {
+ close(sock);
+ return ETIME;
+ }
+
+ bytes = recvfrom(sock,dest,*dsize,0,NULL,NULL);
+ if (bytes < 0)
+ {
+ int err = errno;
+ close(sock);
+ return err;
+ }
+
+ *dsize = bytes;
+ close(sock);
+ return 0;
+}
+
+/**************************************************************************/
diff -r 3bd5c2e9e8ac -r fee6b517c6d4 contrib/spcdns/src/netsimple.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/spcdns/src/netsimple.h Wed Sep 19 15:25:04 2012 +0300
@@ -0,0 +1,75 @@
+/*************************************************************************
+*
+* Copyright 2010 by Sean Conner. All Rights Reserved.
+*
+* 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 3 of the License, or (at your
+* option) any later version.
+*
+* This library is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+* License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with this library; if not, see <http://www.gnu.org/licenses/>.
+*
+**************************************************************************/
+
+/************************************************************************
+*
+* Definitions for a simple network interface to send and receive DNS
+* queries.
+*
+* This only suffices for simple applications; for anything that does a lot
+* of DNS queries, you probably want to use something else.
+*
+* This file assumes C99. You must include the following files before
+* including this one:
+*
+* #include <stdint.h>
+* #include <stddef.h>
+* #include <arpa/inet.h>
+*
+* And if you want to decode the return values (beyond success/failure):
+*
+* #include <errno.h>
+*
+*************************************************************************/
+
+#ifndef NETSIMPLE_H
+#define NETSIMPLE_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#ifndef __GNUC__
+# define __attribute__(x)
+#endif
+
+typedef union sockaddr_all
+{
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+} sockaddr_all;
+
+int net_server (
+ sockaddr_all *const restrict,
+ const char *const restrict
+ ) __attribute__ ((nonnull));
+
+int net_request (
+ sockaddr_all *const restrict,
+ dns_packet_t *const restrict,
+ size_t *const restrict,
+ const dns_packet_t *const restrict,
+ const size_t
+ ) __attribute__ ((nonnull(1,2,3,4)));
+
+#ifdef __cplusplus
+ }
+#endif
+#endif
diff -r 3bd5c2e9e8ac -r fee6b517c6d4 contrib/spcdns/src/test.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/spcdns/src/test.c Wed Sep 19 15:25:04 2012 +0300
@@ -0,0 +1,563 @@
+/*************************************************************************
+*
+* Copyright 2010 by Sean Conner. All Rights Reserved.
+*
+* 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 3 of the License, or (at your
+* option) any later version.
+*
+* This library is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+* License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with this library; if not, see <http://www.gnu.org/licenses/>.
+*
+**************************************************************************/
+
+/**********************************************************************
+*
+* Sample application using my DNS library. It's somewhat similar to dig,
+* but lacking features found in dig. Still useful though, and gives an
+* example of how to use the DNS library.
+*
+* This code is C99.
+*
+***************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include <getopt.h>
+#include <arpa/inet.h>
+
+#include "dns.h"
+#include "mappings.h"
+#include "netsimple.h"
+
+enum
+{
+ OPT_NONE = '\0',
+ OPT_HELP = 'h',
+ OPT_EDNS = 'e',
+ OPT_SERVER = 's',
+ OPT_DUMP = 'd',
+ OPT_ERR = '?'
+};
+
+/************************************************************************/
+
+static void print_question (const char *,dns_question_t *,size_t);
+static void print_answer (const char *,dns_answer_t *,size_t);
+static void usage (const char *);
+static void dump_memory (FILE *,const void *,size_t,size_t);
+
+/************************************************************************/
+
+const struct option c_options[] =
+{
+ { "server" , required_argument , NULL , OPT_SERVER } ,
+ { "edns" , no_argument , NULL , OPT_EDNS } ,
+ { "dump" , no_argument , NULL , OPT_DUMP } ,
+ { "help" , no_argument , NULL , OPT_HELP } ,
+ { NULL , 0 , NULL , 0 }
+};
+
+/***********************************************************************/
+
+int main(int argc,char *argv[])
+{
+ const char *serverhost;
+ const char *host;
+ const char *type;
+ bool fdump;
+ bool fedns;
+ int option;
+ int rc;
+
+ /*-------------------------------------------------------------------------
+ ; verbiage to parse the command line and set some sane defaults, yada yada
+ ; blah blah blah
+ ;------------------------------------------------------------------*/
+
+ serverhost = "127.0.0.1";
+ host = "examle.net";
+ type = "A";
+ fdump = false;
+ fedns = false;
+ option = 0;
+ opterr = 0; /* prevent getopt_long() from printing error messages */
+
+ while(true)
+ {
+ rc = getopt_long(argc,argv,"hdes:",c_options,&option);
+ if (rc == EOF) break;
+
+ switch(rc)
+ {
+ default:
+ case OPT_ERR:
+ fprintf(stderr,"unknown option '%c'\n",optopt);
+ case OPT_HELP:
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ case OPT_SERVER:
+ serverhost = optarg;
+ break;
+ case OPT_EDNS:
+ fedns = true;
+ break;
+ case OPT_DUMP:
+ fdump = true;
+ break;
+ case OPT_NONE:
+ break;
+ }
+ }
+
+ if (optind == argc)
+ {
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ host = argv[optind++];
+
+ if (optind < argc)
+ type = argv[optind];
+
+ /*------------------------------------------------------------------------
+ ; Encoding of a DNS query. I'm finding that many (if not all) DNS servers
+ ; only accept a single question, even though the protocol seems to allow
+ ; more than one question. If there *is* a DNS server that can handle
+ ; multiple questions, then we can handle them, even if they don't exist
+ ; yet.
+ ;--------------------------------------------------------------------*/
+
+ dns_question_t domain;
+ dns_query_t query;
+ dns_packet_t request[DNS_BUFFER_UDP];
+ size_t reqsize;
+ edns0_opt_t opt;
+ dns_answer_t edns;
+
+ domain.name = host;
+ domain.type = dns_type_value(type);
+ domain.class = CLASS_IN;
+
+ query.id = 1234; /* should be a random value */
+ query.query = true;
+ query.opcode = OP_QUERY;
+ query.aa = false;
+ query.tc = false;
+ query.rd = true;
+ query.ra = false;
+ query.ad = false;
+ query.cd = false;
+ query.rcode = RCODE_OKAY;
+ query.qdcount = 1;
+ query.questions = &domain;
+ query.ancount = 0;
+ query.answers = NULL;
+ query.nscount = 0;
+ query.nameservers = NULL;
+ query.arcount = 0;
+ query.additional = NULL;
+
+ if (fedns)
+ {
+ /*----------------------------------------------------------------------
+ ; Test EDNS0 by sending an NSID OPT RR type query.
+ ;
+ ; The udp_payload is the largest UDP packet we can reasonably expect to
+ ; receive. I'm using the value 1464 since that's about the largest UDP
+ ; packet that can fit into an Ethernet frame (20 bytes IP header, 8
+ ; bytes UDP header; RFC-1042 based Ethernet frame).
+ ;
+ ; Additionally, OPT RRs *MUST* be in the additional section of a DNS
+ ; packet, and there can be only one (Highlander 2 & 3? Never happened;
+ ; neither did the TV series) OPT RR.
+ ;----------------------------------------------------------------------*/
+
+ opt.code = EDNS0RR_NSID;
+ opt.data = (uint8_t *)"MY-DNS-SERVER-ID";
+ opt.len = strlen((char *)opt.data);
+
+ edns.opt.name = ".";
+ edns.opt.type = RR_OPT;
+ edns.opt.class = CLASS_UNKNOWN;
+ edns.opt.ttl = 0;
+ edns.opt.udp_payload = 1464;
+ edns.opt.version = 0;
+ edns.opt.fdo = false;
+ edns.opt.numopts = 1;
+ edns.opt.opts = &opt;
+
+ query.arcount = 1;
+ query.additional = &edns;
+ }
+
+ reqsize = sizeof(request);
+ rc = dns_encode(request,&reqsize,&query);
+ if (rc != RCODE_OKAY)
+ {
+ fprintf(stderr,"dns_encode() = (%d) %s\n",rc,dns_rcode_text(rc));
+ return EXIT_FAILURE;
+ }
+
+ if (fdump)
+ {
+ printf("OUTGOING:\n\n");
+ dump_memory(stdout,request,reqsize,0);
+ }
+
+ /*-----------------------------------------------------------------------
+ ; Sending a DNS query. This uses the simple interface provided and is
+ ; not good for much *except* as an example. If you have any complex
+ ; requirements, do not look to this code.
+ ;-----------------------------------------------------------------------*/
+
+ sockaddr_all server;
+ dns_packet_t reply[DNS_BUFFER_UDP];
+ size_t replysize;
+
+ rc = net_server(&server,serverhost);
+ if (rc != 0)
+ {
+ fprintf(stderr,"net_server() = %s",strerror(rc));
+ return EXIT_FAILURE;
+ }
+
+ replysize = sizeof(reply);
+ if (net_request(&server,reply,&replysize,request,reqsize) < 0)
+ {
+ fprintf(stderr,"failure\n");
+ return EXIT_FAILURE;
+ }
+
+ if (fdump)
+ {
+ printf("\nINCOMING:\n\n");
+ dump_memory(stdout,reply,replysize,0);
+ }
+
+ /*----------------------------------------------------------------------
+ ; Decode a DNS packet into something we can use. dns_decoded_t is a type
+ ; to ensure proper alignment for stack based results---this must be big
+ ; enough to handle not only the dns_query_t but additional information as
+ ; well. The 4K size so far seems good enough for decoding UDP packets,
+ ; although I'm using the 8K size just in case.
+ ;-----------------------------------------------------------------------*/
+
+ dns_decoded_t bufresult[DNS_DECODEBUF_8K];
+ size_t bufsize;
+ dns_query_t *result;
+
+ bufsize = sizeof(bufresult);
+ rc = dns_decode(bufresult,&bufsize,reply,replysize);
+ if (rc != RCODE_OKAY)
+ {
+ fprintf(stderr,"dns_decode() = (%d) %s\n",rc,dns_rcode_text(rc));
+ return EXIT_FAILURE;
+ }
+
+ if (fdump)
+ printf("\nBytes used: %lu\n\n",(unsigned long)bufsize);
+
+ result = (dns_query_t *)bufresult;
+
+ /*-------------------------------------------
+ ; Print the results out, ala dig
+ ;-------------------------------------------*/
+
+ printf(
+ "; Questions = %lu\n"
+ "; Answers = %lu\n"
+ "; Name Servers = %lu\n"
+ "; Additional Records = %lu\n"
+ "; Authoritative Result = %s\n"
+ "; Truncated Result = %s\n"
+ "; Recursion Desired = %s\n"
+ "; Recursion Available = %s\n"
+ "; Result = %s\n",
+ (unsigned long)result->qdcount,
+ (unsigned long)result->ancount,
+ (unsigned long)result->nscount,
+ (unsigned long)result->arcount,
+ result->aa ? "true" : "false",
+ result->tc ? "true" : "false",
+ result->rd ? "true" : "false",
+ result->ra ? "true" : "false",
+ dns_rcode_text(result->rcode)
+ );
+
+ print_question("QUESTIONS" ,result->questions ,result->qdcount);
+ print_answer ("ANSWERS" ,result->answers ,result->ancount);
+ print_answer ("NAMESERVERS" ,result->nameservers ,result->nscount);
+ print_answer ("ADDITIONAL" ,result->additional ,result->arcount);
+
+ return EXIT_SUCCESS;
+}
+
+/************************************************************************/
+
+static void print_question(const char *tag,dns_question_t *pquest,size_t cnt)
+{
+ assert(tag != NULL);
+ assert(pquest != NULL);
+
+ printf("\n;;; %s\n\n",tag);
+ for (size_t i = 0 ; i < cnt ; i++)
+ {
+ printf(
+ ";%s %s %s\n",
+ pquest[i].name,
+ dns_class_text(pquest[i].class),
+ dns_type_text (pquest[i].type)
+ );
+ }
+}
+
+/***********************************************************************/
+
+static void print_answer(const char *tag,dns_answer_t *pans,size_t cnt)
+{
+ char ipaddr[INET6_ADDRSTRLEN];
+
+ assert(tag != NULL);
+ assert(pans != NULL);
+
+ printf("\n;;; %s\n\n",tag);
+
+ for (size_t i = 0 ; i < cnt ; i++)
+ {
+ if (pans[i].generic.type != RR_OPT)
+ {
+ printf(
+ "%-16s\t%5lu\t%s\t%s\t",
+ pans[i].generic.name,
+ (unsigned long)pans[i].generic.ttl,
+ dns_class_text(pans[i].generic.class),
+ dns_type_text (pans[i].generic.type)
+ );
+ }
+ else
+ printf("; OPT RR");
+
+ switch(pans[i].generic.type)
+ {
+ case RR_NS:
+ printf("%s",pans[i].ns.nsdname);
+ break;
+ case RR_A:
+ inet_ntop(AF_INET,&pans[i].a.address,ipaddr,sizeof(ipaddr));
+ printf("%s",ipaddr);
+ break;
+ case RR_AAAA:
+ inet_ntop(AF_INET6,&pans[i].aaaa.address,ipaddr,sizeof(ipaddr));
+ printf("%s",ipaddr);
+ break;
+ case RR_CNAME:
+ printf("%s",pans[i].cname.cname);
+ break;
+ case RR_MX:
+ printf("%5d %s",pans[i].mx.preference,pans[i].mx.exchange);
+ break;
+ case RR_PTR:
+ printf("%s",pans[i].ptr.ptr);
+ break;
+ case RR_HINFO:
+ printf("\"%s\" \"%s\"",pans[i].hinfo.cpu,pans[i].hinfo.os);
+ break;
+ case RR_MINFO:
+ printf("(\n\t\t\"%s\"\n\t\t\"%s\" )",pans[i].minfo.rmailbx,pans[i].minfo.emailbx);
+ break;
+ case RR_SPF:
+ case RR_TXT:
+ if (pans[i].txt.len < 30)
+ printf("\"%s\"",pans[i].txt.text);
+ else
+ {
+ size_t len;
+ int max;
+ size_t off;
+
+ printf("(");
+ len = pans[i].txt.len;
+ off = 0;
+
+ while(len)
+ {
+ max = (len > 64) ? 64 : (int)len;
+ printf("\n\t\"%*.*s\"",max,max,&pans[i].txt.text[off]);
+ off += max;
+ len -= max;
+ }
+
+ printf("\n\t\t)\n");
+ }
+ break;
+ case RR_SOA:
+ printf(
+ "%s %s (\n"
+ "\t\t%10lu ; Serial\n"
+ "\t\t%10lu ; Refresh\n"
+ "\t\t%10lu ; Retry\n"
+ "\t\t%10lu ; Expire\n"
+ "\t\t%10lu ) ; Miminum\n",
+ pans[i].soa.mname,
+ pans[i].soa.rname,
+ (unsigned long)pans[i].soa.serial,
+ (unsigned long)pans[i].soa.refresh,
+ (unsigned long)pans[i].soa.retry,
+ (unsigned long)pans[i].soa.expire,
+ (unsigned long)pans[i].soa.minimum
+ );
+ break;
+ case RR_NAPTR:
+ printf(
+ "%5d %5d (\n"
+ "\t\t\"%s\"\n"
+ "\t\t\"%s\"\n"
+ "\t\t\"%s\"\n"
+ "\t\t%s )\n",
+ pans[i].naptr.order,
+ pans[i].naptr.preference,
+ pans[i].naptr.flags,
+ pans[i].naptr.services,
+ pans[i].naptr.regexp,
+ pans[i].naptr.replacement
+ );
+ break;
+ case RR_LOC:
+ printf(
+ "(\n"
+ "\t\t%3d %2d %2d %s ; Latitude\n"
+ "\t\t%3d %2d %2d %s ; Longitude\n"
+ "\t\t%11ld ; Altitude\n"
+ "\t\t%11lu ; Size\n"
+ "\t\t%11lu ; Horizontal Precision\n"
+ "\t\t%11lu ; Vertical Precision\n"
+ "\t\t)\n",
+ pans[i].loc.latitude.deg,
+ pans[i].loc.latitude.min,
+ pans[i].loc.latitude.sec,
+ pans[i].loc.latitude.nw ? "N" : "S",
+ pans[i].loc.longitude.deg,
+ pans[i].loc.longitude.min,
+ pans[i].loc.longitude.sec,
+ pans[i].loc.longitude.nw ? "W" : "E",
+ pans[i].loc.altitude,
+ pans[i].loc.size,
+ pans[i].loc.horiz_pre,
+ pans[i].loc.vert_pre
+ );
+ break;
+ case RR_SRV:
+ printf(
+ "%5d %5d %5d %s",
+ pans[i].srv.priority,
+ pans[i].srv.weight,
+ pans[i].srv.port,
+ pans[i].srv.target
+ );
+ break;
+ case RR_OPT:
+ printf(
+ "\n"
+ ";\tpayload = %lu\n"
+ ";\tDO = %s\n"
+ ";\t#opts = %lu\n",
+ (unsigned long)pans[i].opt.udp_payload,
+ pans[i].opt.fdo ? "true" : "false",
+ (unsigned long)pans[i].opt.numopts
+ );
+ break;
+
+ default:
+ break;
+ }
+ printf("\n");
+ }
+}
+
+/*********************************************************************/
+
+static void usage(const char *prog)
+{
+ assert(prog != NULL);
+
+ fprintf(
+ stderr,
+ "usage: %s [-h] [-d] [-e] [-s server] host [type]\n"
+ "\t-h\t\tusage text (this text)\n"
+ "\t-d\t\tdump raw DNS queries\n"
+ "\t-e\t\tInclude EDNS0 RR with query\n"
+ "\t-s server\tIP address of server\n"
+ "\n"
+ "\ttype\t\tRR DNS type\n",
+ prog
+ );
+}
+
+/**********************************************************************/
+
+#define LINESIZE 16
+
+static void dump_memory(FILE *out,const void *data,size_t size,size_t offset)
+{
+ const unsigned char *block = data;
+ char ascii[LINESIZE + 1];
+ int skip;
+ int j;
+
+ assert(out != NULL);
+ assert(block != NULL);
+ assert(size > 0);
+
+ while(size > 0)
+ {
+ fprintf(out,"%08lX: ",(unsigned long)offset);
+
+ for (skip = offset % LINESIZE , j = 0 ; skip ; j++ , skip--)
+ {
+ fputs(" ",out);
+ ascii[j] = ' ';
+ }
+
+ do
+ {
+ fprintf(out,"%02x ",*block);
+ if (isprint(*block))
+ ascii[j] = *block;
+ else
+ ascii[j] = '.';
+
+ block++;
+ offset++;
+ j++;
+ size--;
+ } while((j < LINESIZE) && (size > 0));
+
+ ascii[j] = '\0';
+
+ if (j < LINESIZE)
+ {
+ int i;
+
+ for (i = j ; i < LINESIZE ; i++)
+ fputs(" ",out);
+ }
+ fprintf(out,"%s\n",ascii);
+ }
+}
+
+/**********************************************************************/
+
More information about the Zrouter-src
mailing list