├── .gitignore
├── Changes
├── LICENSE
├── Makefile
├── README
├── lua
├── dns.lua
├── mx.lua
└── test.lua
├── notes
├── org.conman.dns-2.1.3-1.rockspec
└── src
├── codec.c
├── dns.h
├── dotest.c
├── luadns.c
├── mappings.c
├── mappings.h
├── netsimple.c
├── netsimple.h
├── output.c
└── output.h
/.gitignore:
--------------------------------------------------------------------------------
1 | *.o
2 | *.a
3 | *.so
4 | *~
5 |
--------------------------------------------------------------------------------
/Changes:
--------------------------------------------------------------------------------
1 |
2 | v2.0.0
3 |
4 | * Encoding of multiple DNS records now supported
5 | * Lua now returns integer error instead of string (API change for Lua)
6 |
7 | v1.0.19
8 |
9 | * Fix compilation errors when using Lua 5.1
10 |
11 | v1.0.18
12 |
13 | * Update code to compile with Lua 5.4
14 |
15 | v1.0.17
16 |
17 | * Bug fix---Increase packet buffer size in Lua code.
18 |
19 | v1.0.16
20 |
21 | * Bug fix---Forgot to set class field when using OPT RR
22 |
23 | v1.0.15
24 |
25 | * Bug fix---invalid write to memory
26 |
27 | v1.0.14
28 |
29 | * Bug fix---unused bit goes into the z field
30 |
31 | v1.0.13
32 |
33 | * Bug fix---compiling/linking issues
34 |
35 | v1.0.12
36 |
37 | * Update code to compile with Lua 5.2 and 5.3
38 |
39 | v1.0.11
40 |
41 | * Bug fix---fix typo
42 |
43 | v1.0.10
44 |
45 | * Bug fix---remove undefined behavior from previous bug fix
46 |
47 | v1.0.9
48 |
49 | * Bug fix---concatenated TXT records need space between strings
50 |
51 | v1.0.8
52 |
53 | * Bug fix---timed out condition didn't return timed out error
54 |
55 | v1.0.7
56 |
57 | * Rockspec update
58 |
59 | v1.0.6
60 |
61 | * Rockspec update
62 |
63 | v1.0.5
64 |
65 | * Support for Lua rocks
66 |
67 | v1.0.4
68 |
69 | * Fixed __attribute__()
70 |
71 | v1.0.3
72 |
73 | * Bug fix-return unknown values
74 |
75 | v1.0.2
76 |
77 | * C++ compilation errors fixed
78 |
79 | v1.0.1
80 |
81 | * Added some asserts
82 |
83 | v1.0.0
84 |
85 | * Initial version.
86 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 |
2 | #######################################################################
3 | #
4 | # Copyright 2010 by Sean Conner. All Rights Reserved.
5 | #
6 | # This library is free software; you can redistribute it and/or modify it
7 | # under the terms of the GNU Lesser General Public License as published by
8 | # the Free Software Foundation; either version 3 of the License, or (at your
9 | # option) any later version.
10 | #
11 | # This library is distributed in the hope that it will be useful, but
12 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 | # License for more details.
15 | #
16 | # You should have received a copy of the GNU Lesser General Public License
17 | # along with this library; if not, see .
18 | #
19 | ######################################################################
20 |
21 | UNAME := $(shell uname)
22 | VERSION := $(shell git describe --tag)
23 |
24 | ifeq ($(VERSION),)
25 | VERSION=v2.1.3
26 | endif
27 |
28 | # ===================================================
29 |
30 | CC = gcc -std=c99 -Wall -Wextra -pedantic -Wwrite-strings
31 | CFLAGS = -g
32 | LDFLAGS = -g
33 | LDLIBS = -lm
34 |
35 | ifeq ($(UNAME),Linux)
36 | CSHARE = -fPIC
37 | LDSHARE = -g -shared
38 | endif
39 |
40 | ifeq ($(UNAME),Darwin)
41 | CSHARE = -fPIC
42 | LDSHARE = -g -bundle -undefined dynamic_lookup -all_load
43 | endif
44 |
45 | #=================================================
46 |
47 | INSTALL = /usr/bin/install
48 | INSTALL_PROGRAM = $(INSTALL)
49 | INSTALL_DATA = $(INSTALL) -m 644
50 |
51 | prefix = /usr/local
52 | libdir = $(prefix)/lib
53 |
54 | LUA ?= lua
55 | LUA_VERSION := $(shell $(LUA) -e "print(_VERSION:match '^Lua (.*)')")
56 | LIBDIR ?= $(libdir)/lua/$(LUA_VERSION)
57 |
58 | ifneq ($(LUA_INCDIR),)
59 | src/dns.so : override CFLAGS += -I$(LUA_INCDIR)
60 | endif
61 |
62 | #=================================================
63 |
64 | %.a :
65 | $(AR) $(ARFLAGS) $@ $?
66 |
67 | %.oo : %.c
68 | $(CC) $(CFLAGS) -DVERSION='"$(VERSION)"' $(CSHARE) -c -o $@ $<
69 |
70 | %.so :
71 | $(CC) $(LDSHARE) -o $@ $^
72 |
73 | #=================================================
74 |
75 | .PHONY: all install-lua uninstall-lua clean dist depend
76 | all : src/dotest src/libspcdns.a src/dns.so
77 |
78 | src/dotest : src/dotest.o src/libspcdns.a
79 | src/libspcdns.a : src/codec.o src/mappings.o src/netsimple.o src/output.o
80 | src/dns.so : src/luadns.oo src/codec.oo src/mappings.oo src/netsimple.oo
81 |
82 | install-lua : src/dns.so
83 | $(INSTALL) -d $(DESTDIR)$(LIBDIR)/org/conman
84 | $(INSTALL_PROGRAM) src/dns.so $(DESTDIR)$(LIBDIR)/org/conman
85 |
86 | uninstall-lua :
87 | $(RM) $(DESTDIR)$(LIBDIR)/org/conman/dns.so
88 |
89 | clean:
90 | $(RM) $(shell find . -name '*.o')
91 | $(RM) $(shell find . -name '*.so')
92 | $(RM) $(shell find . -name '*.oo')
93 | $(RM) $(shell find . -name '*.a')
94 | $(RM) $(shell find . -name '*~')
95 | $(RM) Makefile.bak src/dotest
96 |
97 | dist:
98 | git archive -o /tmp/spcdns-$(VERSION).tar.gz --prefix spcdns/ $(VERSION)
99 |
100 | depend:
101 | makedepend -Y -- $(CFLAGS) -- src/*.c 2>/dev/null
102 |
103 | # DO NOT DELETE
104 |
105 | src/codec.o: src/dns.h
106 | src/dotest.o: src/dns.h src/mappings.h src/netsimple.h src/output.h
107 | src/luadns.o: src/dns.h src/mappings.h src/netsimple.h
108 | src/mappings.o: src/dns.h src/mappings.h
109 | src/netsimple.o: src/dns.h src/netsimple.h
110 | src/output.o: src/dns.h src/mappings.h src/output.h
111 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 |
2 | SPCDNS: The sane DNS encoding/decoding library
3 |
4 | SPCDNS implements a simple yet sane API to encode DNS queries and to decode
5 | DNS replies. The library (v2.0.0) currently supports the encoding and
6 | decoding of 30 DNS resource records, which is more than just about all other
7 | DNS resolving libraries I've seen (c-ares, udns, adns, libdns and djbdns
8 | [1]).
9 |
10 | SPCDNS is *NOT* a general purpose DNS resolving library (although code is
11 | provided to make DNS queries, it is simple and fairly stupid). This code
12 | exists to provide a simple method of encoding and decoding the DNS protocol
13 | and thus the network side of things is a bit lacking I'll admit. But that
14 | is beyond what I wanted for this project anyway.
15 |
16 | In the "src/" directory you'll find the following:
17 |
18 | dns.h
19 |
20 | Defines the various DNS RR types, a structure for an
21 | in-memory representation of each RR type (which is what
22 | you'll get back when you call the decoding routine), and the
23 | definitions for two functions, dns_encode() and dns_decode()
24 | which pretty much do what they say.
25 |
26 | codec.c
27 |
28 | The actual implementations of dns_encode() and dns_decode().
29 | This is the only file that's needed to encode and decode the
30 | raw DNS protocol. The routines are thread safe, do *not*
31 | allocate memory (see below for more details) and do not use
32 | signals. It also does not use code from any other file in
33 | this package.
34 |
35 | mappings.h
36 | mappings.c
37 |
38 | These files provide definitions and implementation of a few
39 | helpful routines that return string representations of the
40 | DNS RR types, classes, opcodes and errors. Again, thread
41 | safe and no memory allocations made.
42 |
43 | netsimple.h
44 | netsimple.c
45 |
46 | These files provide definitions and implementations for
47 | making simple DNS queries to a given server. This code is
48 | *simple* and *dumb*, it may be good for light usage but was
49 | written to get actual DNS packets from a DNS server for
50 | testing. This uses UDP and is thus limited to a query of
51 | 512 bytes or less.
52 |
53 | output.h
54 | output.c
55 |
56 | These files provide definitions and implementations for
57 | utility functions to print query results using C stdio.
58 | It was factored out of the unit tests for debugging client
59 | applications making using of libspcdns.a and libspcdns.so.
60 | They are found in the libspcdnsmisc.a and libspcdnsmisc.so
61 | libraries.
62 |
63 | luadns.c
64 |
65 | Lua [2] bindings for this library. It exports the routines
66 | found in codec.c, mappings.c and netsimple.c.
67 |
68 | dotest.c
69 |
70 | An example program showing how to use the API to construct
71 | and send a query, and to decode the response.
72 |
73 | You'll probably want to check the Makefile to make sure the right compiler
74 | and locations are set. Or not. You don't *HAVE* to use the included
75 | Makefile. It's really just a set of suggestions anyway.
76 |
77 | A NOTE ABOUT MEMORY ALLOCATIONS
78 |
79 | The dns_encode() and dns_decode() functions do no memory allocation; they
80 | use what you give them. In the case of dns_decode(), the block of memory
81 | passed in must be big enough to handle not only the dns_query_t structure,
82 | but multiple dns_answer_t structures and text strings representing domain
83 | names and the occasional string or two (say, for TXT or NAPTR records). In
84 | testing, I've found that 4K for decoding appears to be enough memory to
85 | handle DNS requests made via UDP (although the test.c program uses an 8K
86 | buffer).
87 |
88 | This block of memory should be properly aligned and to help make that easier
89 | I've defined two data types that should allow proper alignment, along with
90 | some useful constants to declare buffers of proper alignment and size.
91 |
92 | dns_packet_t reply [DNS_BUFFER_UDP];
93 | dns_decoded_t decoded[DNS_DECODEBUF_4K];
94 | dns_query_t *result;
95 | dns_rcode rc;
96 | size_t replysize;
97 | size_t decodesize;
98 |
99 | /* assume reply contains a DNS packet, and replysize is set */
100 |
101 | decodesize = sizeof(decoded);
102 | rc = dns_decode(decoded,&decodesize,reply,replysize);
103 |
104 | if (rc != RCODE_OKAY)
105 | {
106 | /* handle error */
107 | }
108 |
109 | result = (dns_query_t *)decoded;
110 |
111 | /* go with processing the result */
112 |
113 | Do *NOT* assume that DNS_DECODEBUF_4K is equal to 4096---it's not. It
114 | *DOES*, however, result in at least a 4K block of memory made up of
115 | DNS_DECODEBUF_4K worth of dns_decoded_t types. By the same token, do *NOT*
116 | assume that DNS_BUFFER_UDP is 512, but it too, does result in a buffer of at
117 | least 512 bytes made up of DNS_BUFFER_UDP dns_packet_t types.
118 |
119 | And while passing in a char * declared buffer to dns_decode() may appear to
120 | work, it only works on *YOUR* system; it may not work on other systems.
121 |
122 | A NOTE ABOUT DOMAIN NAMES
123 |
124 | The dns_encode() function assumes the domain passed is a fully qualified
125 | domain name. If you see an RCODE_NAME_ERROR when calling this function, you
126 | are probably not passing in a FQDN (if you are and are still getting that
127 | error, it's most likely a domain name segment exceeding the 63 character DNS
128 | limit).
129 |
130 | SOME NOTES ABOUT THE LUA BINDINGS
131 |
132 | The Lua bindings (for Lua 5.1-5.4) are loaded into a Lua script with the
133 | following:
134 |
135 | local dns = require "org.conman.dns"
136 |
137 | Doing a "make install-lua" will install this file under:
138 |
139 | /usr/local/lib/lua//org/conman/
140 |
141 | (assuming you didn't change the LUA setting in the Makefile)
142 |
143 | and thus place it under the appropriate namespace so Lua can find it.
144 |
145 | The file "lua/test.lua" shows the best use of the Lua bindings (and is close
146 | enough to what "src/test.c" does). Better network handling could be done
147 | using LuaSocket, but for that, you are on your own.
148 |
149 | UNIT TESTING
150 |
151 | The dotest program allows unit-testing SPCDNS when making changes or
152 | integrating it with client applications.
153 |
154 | Note: the unit test program, dotest, requires a fully-qualified canonical DNS
155 | name. This means "www.example.com." NOT "www.example.com". If this is not
156 | present, the dns_encode_domain function returns RCODE_NAME_ERROR and the test
157 | will fail with a mysterious error message.
158 |
159 | Sample Output:
160 |
161 | This is an example of a working run, querying for Google's web server, using a
162 | Google Public DNS Server [4].
163 |
164 | $ ./dotest -d -s 8.8.8.8 www.google.com.
165 | OUTGOING:
166 |
167 | ... MEMORY DUMP...
168 |
169 | INCOMING:
170 |
171 | ... MEMORY DUMP...
172 |
173 | Bytes used: 680
174 |
175 | ; Questions = 1
176 | ; Answers = 5
177 | ; Name Servers = 0
178 | ; Additional Records = 0
179 | ; Authoritative Result = false
180 | ; Truncated Result = false
181 | ; Recursion Desired = true
182 | ; Recursion Available = true
183 | ; Result = No error
184 |
185 | ;;; QUESTIONS
186 |
187 | ;www.google.com. IN A
188 |
189 | ;;; ANSWERS
190 |
191 | www.google.com. 185 IN A 74.125.239.49
192 | www.google.com. 185 IN A 74.125.239.52
193 | www.google.com. 185 IN A 74.125.239.50
194 | www.google.com. 185 IN A 74.125.239.51
195 | www.google.com. 185 IN A 74.125.239.48
196 |
197 | ;;; NAMESERVERS
198 |
199 |
200 | ;;; ADDITIONAL
201 |
202 | A FINAL NOTE
203 |
204 | If you have any problems, questions or enhancements, please send them my
205 | way, to sean@conman.org.
206 |
207 | Thank you.
208 |
209 | Other contributors include, but are not limited to:
210 |
211 | Matthew Hall
212 |
213 | [1] http://c-ares.haxx.se/
214 | http://www.corpit.ru/mjt/udns.html
215 | http://www.chiark.greenend.org.uk/~ian/adns/
216 | http://www.25thandclement.com/~william/projects/dns.c.html
217 | http://cr.yp.to/djbdns.html
218 |
219 | [2] http://www.lua.org/
220 |
221 | [3] http://w3.impa.br/~diego/software/luasocket/
222 |
223 | [4] https://developers.google.com/speed/public-dns/
224 |
--------------------------------------------------------------------------------
/lua/dns.lua:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env lua
2 | -- *************************************************************************
3 | --
4 | -- Copyright 2010 by Sean Conner. All Rights Reserved.
5 | --
6 | -- This library is free software; you can redistribute it and/or modify it
7 | -- under the terms of the GNU Lesser General Public License as published by
8 | -- the Free Software Foundation; either version 3 of the License, or (at your
9 | -- option) any later version.
10 | --
11 | -- This library is distributed in the hope that it will be useful, but
12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 | -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 | -- License for more details.
15 | --
16 | -- You should have received a copy of the GNU Lesser General Public License
17 | -- along with this library; if not, see .
18 | --
19 | -- **************************************************************************
20 |
21 | local dns = require "org.conman.dns"
22 |
23 | local e = dns.encode {
24 | id = 1234,
25 | query = true,
26 | rd = true,
27 | opcode = 'query',
28 | question = {
29 | name = 'yahoo.com.',
30 | type = 'mx',
31 | class = 'in'
32 | }
33 | }
34 |
35 | local r,err = dns.query('127.0.0.1',e)
36 |
37 | if r == nil then
38 | print("error:",err)
39 | os.exit(1)
40 | end
41 |
42 | local d = dns.decode(r)
43 |
44 | for i = 1 , #d.answers do
45 | print(string.format("%s %d %s %s %d %s",
46 | d.answers[i].name,
47 | d.answers[i].ttl,
48 | d.answers[i].class,
49 | d.answers[i].type,
50 | d.answers[i].preference,
51 | d.answers[i].exchange
52 | ))
53 | end
54 |
55 |
--------------------------------------------------------------------------------
/lua/mx.lua:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env lua
2 | -- *************************************************************************
3 | --
4 | -- Copyright 2010 by Sean Conner. All Rights Reserved.
5 | --
6 | -- This library is free software; you can redistribute it and/or modify it
7 | -- under the terms of the GNU Lesser General Public License as published by
8 | -- the Free Software Foundation; either version 3 of the License, or (at your
9 | -- option) any later version.
10 | --
11 | -- This library is distributed in the hope that it will be useful, but
12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 | -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 | -- License for more details.
15 | --
16 | -- You should have received a copy of the GNU Lesser General Public License
17 | -- along with this library; if not, see .
18 | --
19 | -- **************************************************************************
20 | -- luacheck: ignore 611
21 |
22 | local SERVER = "127.0.0.1"
23 | local dns = require "org.conman.dns"
24 |
25 | -- **************************************************************
26 |
27 | local function query(host,type)
28 | local e = dns.encode {
29 | id = math.random(65535),
30 | query = true,
31 | rd = true,
32 | opcode = 'query',
33 | question = {
34 | name = host,
35 | type = type,
36 | class = 'in'
37 | }
38 | }
39 |
40 | local r,err = dns.query(SERVER,e)
41 |
42 | if r == nil then
43 | print("error:",err)
44 | return nil
45 | end
46 |
47 | return dns.decode(r)
48 | end
49 |
50 | -- ****************************************************************
51 |
52 | local function query_a(host)
53 | local a,err = query(host,'a')
54 |
55 | if a == nil then
56 | print("error:",err)
57 | return nil
58 | end
59 |
60 | return a.answers[1]
61 | end
62 |
63 | -- ****************************************************************
64 |
65 | local function query_mx(host)
66 | local mx,err = query(host,'mx')
67 |
68 | if mx == nil then
69 | print("error:",err)
70 | return nil
71 | end
72 |
73 | table.sort(mx.answers,function(a,b) return a.preference < b.preference end)
74 |
75 | for i = 1 , #mx.answers do
76 | mx.answers[i].ADDRESS = mx.additional[mx.answers[i].exchange]
77 | if mx.answers[i].ADDRESS == nil then
78 | mx.answers[i].ADDRESS = query_a(mx.answers[i].exchange)
79 | end
80 | end
81 |
82 | return mx.answers
83 | end
84 |
85 | -- **************************************************************
86 |
87 | if #arg == 0 then
88 | io.stderr:write(string.format("usage: %s domain\n",arg[0]))
89 | os.exit(1)
90 | end
91 |
92 | local results = query_mx(arg[1])
93 |
94 | for i = 1 , #results do
95 | local mx,ip
96 |
97 | mx = results[i].exchange
98 | ip = results[i].ADDRESS.address or "(none)"
99 |
100 | print(mx,ip)
101 | end
102 |
--------------------------------------------------------------------------------
/lua/test.lua:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env lua
2 | -- *************************************************************************
3 | --
4 | -- Copyright 2010 by Sean Conner. All Rights Reserved.
5 | --
6 | -- This library is free software; you can redistribute it and/or modify it
7 | -- under the terms of the GNU Lesser General Public License as published by
8 | -- the Free Software Foundation; either version 3 of the License, or (at your
9 | -- option) any later version.
10 | --
11 | -- This library is distributed in the hope that it will be useful, but
12 | -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 | -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 | -- License for more details.
15 | --
16 | -- You should have received a copy of the GNU Lesser General Public License
17 | -- along with this library; if not, see .
18 | --
19 | -- **************************************************************************
20 | -- luacheck: ignore 611
21 |
22 | local SERVER = "127.0.0.1"
23 | local dns = require "org.conman.dns"
24 |
25 | -- **************************************************************
26 |
27 | local function query(host,type)
28 | local e
29 | local r
30 | local err
31 |
32 | e,err = dns.encode {
33 | id = math.random(65535),
34 | query = true,
35 | rd = true,
36 | opcode = 'query',
37 | question = {
38 | name = host,
39 | type = type,
40 | class = 'in'
41 | }
42 | }
43 |
44 | if e == nil then
45 | return e,err
46 | end
47 |
48 | r,err = dns.query(SERVER,e)
49 |
50 | if r == nil then
51 | return r,err
52 | end
53 |
54 | return dns.decode(r)
55 | end
56 |
57 | -- ****************************************************************
58 |
59 | local function print_txt(rec)
60 | if type(rec.text) == 'string' then
61 | return string.format("%q",rec.text)
62 | elseif type(rec.text) == 'table' then
63 | local s = "("
64 | for i = 1 , #rec.text do
65 | s = s .. string.format("\n\t\t\t%q",rec.text[i])
66 | end
67 | s = s .. "\n\t\t)"
68 | return s
69 | else
70 | return ""
71 | end
72 | end
73 |
74 | local callbacks =
75 | {
76 | NS = function(rec) return rec.nsdname end,
77 | A = function(rec) return rec.address end,
78 | AAAA = function(rec) return rec.address end,
79 | CNAME = function(rec) return rec.cname end,
80 | MX = function(rec) return string.format("%5d %s",rec.preference,rec.exchange) end,
81 | PTR = function(rec) return rec.ptr end,
82 | HINFO = function(rec) return string.format("%q %q",rec.cpu,rec.os) end,
83 | SPF = print_txt,
84 | TXT = print_txt,
85 | SOA = function(rec) return string.format([[
86 | %s %s (
87 | %10d ; Serial
88 | %10d ; Refresh
89 | %10d ; Retry
90 | %10d ; Expire
91 | %10d ) ; Miminum
92 | ]],
93 | rec.mname,
94 | rec.rname,
95 | rec.serial,
96 | rec.refresh,
97 | rec.retry,
98 | rec.expire,
99 | rec.minimum ) end,
100 | NAPTR = function(rec) return string.format([[
101 | %5d %5d (
102 | %q
103 | %q
104 | %q
105 | %s )
106 | ]],
107 | rec.order,
108 | rec.preference,
109 | rec.flags,
110 | rec.services,
111 | rec.regexp,
112 | rec.replacement) end,
113 | SRV = function(rec) return string.format(
114 | "%5d %5d %5d %s",
115 | rec.priority,
116 | rec.weight,
117 | rec.port,
118 | rec.target) end,
119 | LOC = function(rec) return string.format([[
120 | (
121 | %3d %2d %2d %s ; Latitude
122 | %3d %2d %2d %s ; Longitude
123 | %11d ; Altitude
124 | %11d ; Size
125 | %11d ; Horizontal Precision
126 | %11d ; Vertical Precision
127 | )
128 | ]],
129 | rec.latitude.deg,
130 | rec.latitude.min,
131 | rec.latitude.sec,
132 | rec.latitude.hemisphere,
133 | rec.longitude.deg,
134 | rec.longitude.min,
135 | rec.longitude.sec,
136 | rec.longitude.hemisphere,
137 | rec.altitude,
138 | rec.size,
139 | rec.horiz_pre,
140 | rec.vert_pre ) end
141 | }
142 |
143 | local function print_answers(tag,recs)
144 | io.stdout:write(string.format("\n;;; %s\n\n",tag))
145 |
146 | for i = 1 , #recs do
147 | local s = string.format("%-16s\t%d\t%s\t%s\t",
148 | recs[i].name,
149 | recs[i].ttl,
150 | recs[i].class,
151 | recs[i].type
152 | )
153 | s = s .. callbacks[recs[i].type](recs[i]) .. "\n"
154 | io.stdout:write(s)
155 | end
156 | end
157 |
158 | -- **********************************************************************
159 |
160 |
161 | if #arg == 0 then
162 | io.stderr:write(string.format("usage: %s type domain\n",arg[0]))
163 | os.exit(1)
164 | end
165 |
166 | local results,err
167 |
168 | results,err = query(arg[2],arg[1])
169 |
170 | if results == nil then
171 | io.stderr:write(string.format(
172 | "error: query(%s,%s) = %s",
173 | arg[2],
174 | arg[1],
175 | err
176 | ))
177 | os.exit(1)
178 | end
179 |
180 | io.stdout:write(string.format([[
181 | ; Questions = 1
182 | ; Answers = %d
183 | ; Name Servers = %d
184 | ; Additional Records = %d
185 | ; Authoritative Result = %s
186 | ; Truncated Result = %s
187 | ; Recursion Desired = %s
188 | ; Recursion Available = %s
189 | ; Result = %s
190 |
191 | ;;; QUESTIONS
192 |
193 | ; %s %s %s
194 | ]],
195 | #results.answers,
196 | #results.nameservers,
197 | #results.additional,
198 | tostring(results.aa),
199 | tostring(results.tc),
200 | tostring(results.rd),
201 | tostring(results.ra),
202 | results.rcode,
203 | results.question.name,
204 | results.question.class,
205 | results.question.type
206 | ))
207 |
208 | print_answers("ANSWERS" , results.answers)
209 | print_answers("NAMESERVERS" , results.nameservers)
210 | print_answers("ADDITIONAL" , results.additional)
211 |
212 | os.exit(0)
213 |
--------------------------------------------------------------------------------
/notes:
--------------------------------------------------------------------------------
1 | https://www.netmeister.org/blog/https-rrs.html
2 | via https://lobste.rs/s/z5ogrr/use_https_resource_records
3 |
4 |
5 | https://www.netmeister.org/blog/tlds.html
6 | https://www.netmeister.org/blog/dns-rrs.html
7 |
8 | On avoiding malloc:
9 |
10 | http://spin.atomicobject.com/2012/11/01/hey-c-is-a-functional-language-too/
11 |
12 |
13 | On Ruby bindings:
14 |
15 | http://onlamp.com/pub/a/onlamp/2004/11/18/extending_ruby.html
16 |
17 | ---
18 |
19 | Google: extending Ruby in C
20 |
21 | ---
22 |
23 | https://github.com/avsm/melange/blob/master/lib/dns/dns_rr.mpl
24 |
25 | http://www.bind9.net/dns-parameters
26 |
27 |
--------------------------------------------------------------------------------
/org.conman.dns-2.1.3-1.rockspec:
--------------------------------------------------------------------------------
1 | package = "org.conman.dns"
2 | version = "2.1.3-1"
3 | source = {
4 | url = "git+https://github.com/spc476/SPCDNS.git",
5 | tag = "v2.1.3"
6 | }
7 | description = {
8 | summary = "A Lua module to encode DNS queries and decode DNS answers.",
9 | detailed = [[
10 | A simple interface to encode and decode DNS queries. This supports
11 | most of the commonly used DNS records and is meant to be a low level
12 | API upon which a generalized DNS query system can be built.
13 | ]],
14 | homepage = "http://www.conman.org/software/spcdns/",
15 | license = "LGPL",
16 | maintainer = "Sean Conner "
17 | }
18 | dependencies = {
19 | "lua >= 5.1, <= 5.4"
20 | }
21 | build = {
22 | type = "make",
23 | platforms = {
24 | linux = {
25 | build_variables = {
26 | CC = "gcc -std=c99"
27 | }
28 | },
29 | solaris = {
30 | build_varaibles = {
31 | CC = "c99"
32 | }
33 | }
34 | },
35 | build_target = "src/dns.so",
36 | build_variables = {
37 | CC = "$(CC)",
38 | CFLAGS = "$(CFLAGS) -I$(LUA_INCDIR)",
39 | LDSHARE = "$(LIBFLAG)",
40 | LUA = "$(LUA)"
41 | },
42 | install_target = "install-lua",
43 | install_variables = {
44 | LIBDIR = "$(LIBDIR)",
45 | LUA = "$(LUA)"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/dns.h:
--------------------------------------------------------------------------------
1 | /*************************************************************************
2 | *
3 | * Copyright 2010 by Sean Conner. All Rights Reserved.
4 | *
5 | * This library is free software; you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published by
7 | * the Free Software Foundation; either version 3 of the License, or (at your
8 | * option) any later version.
9 | *
10 | * This library is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
13 | * License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this library; if not, see .
17 | *
18 | **************************************************************************/
19 |
20 | /*************************************************************************
21 | *
22 | * Definitions for all things related to the DNS protocol (and not to the
23 | * network transport thereof---that's for another episode).
24 | *
25 | * I've scoured the Internet and I think I've located every DNS RR type that
26 | * exists. And for the majority of them, I've made an in-memory
27 | * representation of said record for easy access to the contents (for when I
28 | * do get around to decoding them from their wire representation). For
29 | * records that I do not decode (and you'll need to check codec.c to see
30 | * which ones aren't being decoded) you'll get back a dns_x_t, which has the
31 | * common portion of the RR decoded (which includes the ID, type, class and
32 | * TTL) plus the remainder of the raw packet.
33 | *
34 | * My eventual intent is to decode those records that I can find definitions
35 | * for, and decipher the sometimes dry and dense RFCs that describe said RRs.
36 | * I'm well on my way with support for about half the known records (which
37 | * includes the ones most likely to be found in 99% of all zone files).
38 | *
39 | * This file assumes C99. You must include the following files before
40 | * including this one:
41 | *
42 | * #include
43 | * #include
44 | * #include
45 | * #incldue
46 | *
47 | ***************************************************************************/
48 |
49 | #ifndef I_52281206_2176_5917_BC9C_574D81892362
50 | #define I_52281206_2176_5917_BC9C_574D81892362
51 |
52 | #include
53 | #include
54 | #if defined(_WIN32)
55 | # include
56 | # ifdef _MSC_VER
57 | # include
58 | # else
59 | # include
60 | # endif
61 | typedef uint32_t in_addr_t;
62 | #elif defined(__unix__) || defined (__APPLE__)
63 | # include
64 | #else
65 | // No platform implementation of in6_addr so we'll provide a simple one
66 | typedef uint32_t in_addr_t;
67 | struct in6_addr
68 | {
69 | union
70 | {
71 | uint8_t u6_addr8[16];
72 | uint16_t u6_addr16[8];
73 | uint32_t u6_addr32[4];
74 | } in6_u;
75 |
76 | # define s6_addr in6_u.u6_addr8
77 | # define s6_addr16 in6_u.u6_addr16
78 | # define s6_addr32 in6_u.u6_addr32
79 | };
80 | #endif
81 |
82 | #ifdef __cplusplus
83 | # define class dclass
84 | # define restrict
85 | extern "C" {
86 | #endif
87 |
88 | #ifndef __GNUC__
89 | # define __attribute__(x)
90 | #endif
91 |
92 | /****************************************************************************
93 | * Buffers passed to these routines should be declared as one of these two
94 | * types with one of the given sizes below, depending upon what the buffer is
95 | * being used for. This is to ensure things work out fine and don't blow up
96 | * (like a segfault). The 4K size *should* be okay for UDP packets, but if
97 | * you are worried, 8K is more than enough to handle responses from UDP.
98 | * Larger sizes may be required for TCP.
99 | *
100 | * A declaration would looke something like:
101 | *
102 | * dns_packet_t query_packet [DNS_BUFFER_UDP];
103 | * dns_decoded_t decoded_response[DNS_DECODEBUF_4K];
104 | *
105 | * Alternatively, you can do this:
106 | *
107 | * dns_packet_t *pquery_packet;
108 | * dns_decoded_t *pdecoded_response;
109 | *
110 | * pquery_packet = malloc(MAX_DNS_QUERY_SIZE);
111 | * pdecoded_response = malloc(4192);
112 | *
113 | *************************************************************************/
114 |
115 | typedef uintptr_t dns_packet_t;
116 | typedef uintptr_t dns_decoded_t;
117 |
118 | #define DNS_BUFFER_UDP ( 512uL / sizeof(dns_packet_t))
119 | #define DNS_BUFFER_UDP_MAX ( 1492uL / sizeof(dns_packet_t))
120 | #define DNS_DECODEBUF_4K ( 4096uL / sizeof(dns_decoded_t))
121 | #define DNS_DECODEBUF_8K ( 8192uL / sizeof(dns_decoded_t))
122 | #define DNS_DECODEBUF_16k (16384uL / sizeof(dns_decoded_t))
123 |
124 | /************************************************************************
125 | * Various upper limits in the DNS protocol
126 | ************************************************************************/
127 |
128 | #define MAX_DNS_QUERY_SIZE 512
129 | #define MAX_DOMAIN_SEGMENT 64
130 | #define MAX_DOMAIN_LABEL 64
131 | #define MAX_STRING_LEN 256
132 | #define MAX_UDP_PACKET_SIZE 1492
133 |
134 | /***************************************************************************
135 | * I've specified where each RR, Class and error codes are defined. Also,
136 | * for the RRs, I've marked if I have decode support as well as experimental
137 | * and obsolete information as follows:
138 | *
139 | * + Encoding/Decoding support
140 | * O Obsolete
141 | * E Experimental
142 | *
143 | * https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml
144 | ***************************************************************************/
145 |
146 | typedef enum dns_type
147 | {
148 | RR_A = 1, /* IPv4 Address + RFC-1035 */
149 | RR_NS = 2, /* Name server + RFC-1035 */
150 | RR_MD = 3, /* Mail Destination O+ RFC-1035 */
151 | RR_MF = 4, /* Mail Forwarder O+ RFC-1035 */
152 | RR_CNAME = 5, /* Canonical name + RFC-1035 */
153 | RR_SOA = 6, /* Start of Authority + RFC-1035 */
154 | RR_MB = 7, /* Mailbox E+ RFC-1035 */
155 | RR_MG = 8, /* Mailgroup E+ RFC-1035 */
156 | RR_MR = 9, /* Mailrename E+ RFC-1035 */
157 | RR_NULL = 10, /* NULL resource E+ RFC-1035 */
158 | RR_WKS = 11, /* Well Known Service + RFC-1035 */
159 | RR_PTR = 12, /* Pointer + RFC-1035 */
160 | RR_HINFO = 13, /* Host Info + RFC-1035 */
161 | RR_MINFO = 14, /* Mailbox/mail list info + RFC-1035 */
162 | RR_MX = 15, /* Mail Exchange + RFC-1035 */
163 | RR_TXT = 16, /* Text + RFC-1035 */
164 | RR_RP = 17, /* Responsible Person + RFC-1183 */
165 | RR_AFSDB = 18, /* Andrew File System DB + RFC-1183 RFC-5864 */
166 | RR_X25 = 19, /* X.25 address, route binding + RFC-1183 */
167 | RR_ISDN = 20, /* ISDN address, route binding + RFC-1183 */
168 | RR_RT = 21, /* Route Through + RFC-1183 */
169 | RR_NSAP = 22, /* Network Service Access Proto + RFC-1348 RFC-1706 */
170 | RR_NSAP_PTR = 23, /* NSAP Pointer + RFC-1348 */
171 | RR_SIG = 24, /* Signature RFC-2065 RFC-2535 RFC-3755 RFC-4034 */
172 | RR_KEY = 25, /* Key RFC-2065 RFC-2535 RFC-3755 RFC-4034 */
173 | RR_PX = 26, /* X.400 mail mapping + RFC-2163 */
174 | RR_GPOS = 27, /* Geographical position O+ RFC-1712 */
175 | RR_AAAA = 28, /* IPv6 Address + RFC-1886 RFC-3596 */
176 | RR_LOC = 29, /* Location + RFC-1876 */
177 | RR_NXT = 30, /* Next RR RFC-2065 RFC-2535 RFC-3755 */
178 | RR_EID = 31, /* Endpoint Identifier */
179 | RR_NIMLOC = 32, /* Nimrod Locator */
180 | RR_SRV = 33, /* Service + RFC-2782 */
181 | RR_ATMA = 34, /* ATM Address */
182 | RR_NAPTR = 35, /* Naming Authority Pointer + RFC-2168 RFC-2915 RFC-3403 */
183 | RR_KX = 36, /* Key Exchange RFC-2230 */
184 | RR_CERT = 37, /* Certification RFC-4398 */
185 | RR_A6 = 38, /* IPv6 Address O RFC-2874 RFC-3658 */
186 | RR_DNAME = 39, /* Non-terminal DNAME (IPv6) RFC-2672 */
187 | RR_SINK = 40, /* Kitchen sink */
188 | RR_OPT = 41, /* EDNS0 option (meta-RR) + RFC-2671 RFC-3225 RFC-6891 */
189 | RR_APL = 42, /* Address Prefix List RFC-3123 */
190 | RR_DS = 43, /* Delegation Signer RFC-3658 RFC-4034 */
191 | RR_SSHFP = 44, /* SSH Key Fingerprint RFC-4255 */
192 | RR_ISECKEY = 45, /* IP Security Key RFC-4025 */
193 | RR_RRSIG = 46, /* Resource Record Signature RFC-3755 RFC-4034 */
194 | RR_NSEC = 47, /* Next Security Record RFC-3755 RFC-4034 */
195 | RR_DNSKEY = 48, /* DNS Security Key RFC-3755 RFC-4034 */
196 | RR_DHCID = 49, /* DHCID RFC-4701 */
197 | RR_NSEC3 = 50, /* NSEC3 RFC-5155 */
198 | RR_NSEC3PARAM = 51, /* NSEC3PARAM RFC-5155 */
199 | RR_TLSA = 52, /* TLSA RFC-6698 */
200 | RR_SMIMEA = 53, /* S/MIME cert association RFC-8162 */
201 | RR_HIP = 55, /* Host Identity Protocol RFC-5205 */
202 | RR_NINFO = 56, /* NINFO */
203 | RR_RKEY = 57, /* RKEY */
204 | RR_TALINK = 58, /* Trust Anchor Link */
205 | RR_CDS = 59, /* Child DS RFC-7344 */
206 | RR_CDNSKEY = 60, /* DNSKEY the Child wants reflected RFC-7344 */
207 | RR_OPENPGPKEY = 61, /* OpenPGP key RFC-7929 */
208 | RR_CSYNC = 62, /* Child-to-Parent Synchronization RFC-7477 */
209 | RR_ZONEMD = 63, /* Message Digest Over Zone Data RFC-8976 */
210 | RR_SVCB = 64, /* Service Binding */
211 | RR_HTTPS = 65, /* HTTPS Binding (really?) */
212 | RR_SPF = 99, /* Sender Policy Framework O+ RFC-4408 RFC-7208 */
213 | RR_UINFO = 100, /* IANA Reserved */
214 | RR_UID = 101, /* IANA Reserved */
215 | RR_GID = 102, /* IANA Reserved */
216 | RR_UNSPEC = 103, /* IANA Reserved */
217 | RR_NID = 104, /* Node Identifier RFC-6742 */
218 | RR_L32 = 105, /* 32-bit Locator value RFC-6742 */
219 | RR_L64 = 106, /* 64-bit Locator value RFC-6742 */
220 | RR_LP = 107, /* Name of ILNP subnetwork RFC-6742 */
221 | RR_EUI48 = 108, /* EUI-48 address RFC-7043 */
222 | RR_EUI64 = 109, /* EUI-64 address RFC-7043 */
223 |
224 | /* Query types, >= 128 */
225 |
226 | RR_TKEY = 249, /* Transaction Key RFC-2930 */
227 | RR_TSIG = 250, /* Transaction Signature RFC-2845 */
228 | RR_IXFR = 251, /* Incremental zone transfer RFC-1995 */
229 | RR_AXFR = 252, /* Transfer of zone RFC-1035 RFC-5936 */
230 | RR_MAILB = 253, /* Mailbox related records RFC-1035 */
231 | RR_MAILA = 254, /* Mail agent RRs (obsolete) O RFC-1035 */
232 | RR_ANY = 255, /* All records RFC-1035 RFC-6895 RFC-8482 */
233 | RR_URI = 256, /* Universal Resource Indicator RFC-7553 */
234 | RR_CAA = 257, /* Certification Authority Restriction RFC-8659 */
235 | RR_AVC = 258, /* Application Visibility and Control */
236 | RR_DOA = 259, /* Digital Object Architecture */
237 | RR_AMTRELAY = 260, /* Automatic Multicast Tunneling Relay RFC-8777 */
238 |
239 | RR_TA = 32768, /* DNSSEC Trust Authories */
240 | RR_DLV = 32769, /* DNSSEC Lookaside Validation O RFC-8749 RFC-4431 */
241 |
242 | RR_PRIVATE = 65280, /* Private usage RFC-2929 */
243 | RR_UNKNOWN = 65535, /* Unknown record type RFC-6895 */
244 | } dns_type_t;
245 |
246 | typedef enum edns0_type
247 | {
248 | EDNS0RR_NSID = 3 /* Name Server ID + RFC-5001 */
249 | } edns0_type_t;
250 |
251 | typedef enum dns_class
252 | {
253 | CLASS_IN = 1, /* Internet RFC-1035 */
254 | CLASS_CS = 2, /* CSNET (obsolete) RFC-1035 */
255 | CLASS_CH = 3, /* CHAOS RFC-1035 */
256 | CLASS_HS = 4, /* Hesiod RFC-1035 */
257 | CLASS_NONE = 254, /* RFC-2136 */
258 | CLASS_ANY = 255, /* All classes RFC-1035 */
259 | CLASS_PRIVATE = 65280, /* Private use RFC-2929 */
260 | CLASS_UNKNOWN = 65535, /* Unknown class RFC-2929 */
261 | } dns_class_t;
262 |
263 | typedef enum dns_op
264 | {
265 | OP_QUERY = 0, /* RFC-1035 */
266 | OP_IQUERY = 1, /* RFC-1035 RFC-3425 */ /* Obsolete */
267 | OP_STATUS = 2, /* RFC-1035 */
268 | OP_NOTIFY = 4, /* RFC-1996 */
269 | OP_UPDATE = 5, /* RFC-2136 */
270 | OP_UNKNOWN = 1 /* Since OP_IQUERY is obsolete */
271 | } dns_op_t;
272 |
273 | typedef enum dns_rcode
274 | {
275 | RCODE_OKAY = 0, /* RFC-1035 */
276 | RCODE_FORMAT_ERROR = 1, /* RFC-1035 */
277 | RCODE_SERVER_FAILURE = 2, /* RFC-1035 */
278 | RCODE_NAME_ERROR = 3, /* RFC-1035 */
279 | RCODE_NOT_IMPLEMENTED = 4, /* RFC-1035 */
280 | RCODE_REFUSED = 5, /* RFC-1035 */
281 | RCODE_YXDOMAIN = 6, /* RFC-2136 */
282 | RCODE_YXRRSET = 7, /* RFC-2136 */
283 | RCODE_NXRRSET = 8, /* RFC-2136 */
284 | RCODE_NOTAUTH = 9, /* RFC-2136 */
285 | RCODE_NOTZONE = 10, /* RFC-2136 */
286 | RCODE_BADVERS = 16, /* RFC-2671 */
287 | RCODE_BADSIG = 16, /* RFC-2845 */
288 | RCODE_BADKEY = 17, /* RFC-2845 */
289 | RCODE_BADTIME = 18, /* RFC-2845 */
290 | RCODE_BADMODE = 19, /* RFC-2845 */
291 | RCODE_BADNAME = 20, /* RFC-2930 */
292 | RCODE_BADALG = 21, /* RFC-2930 */
293 | RCODE_BADTRUC = 22, /* RFC-4635 */
294 | RCODE_BADCOOKIE = 23, /* RFC-7873 */
295 | RCODE_PRIVATE = 3841, /* RFC-2929 */
296 |
297 | RCODE_NO_MEMORY,
298 | RCODE_BAD_STRING,
299 | } dns_rcode_t;
300 |
301 | typedef enum edns0_label
302 | {
303 | EDNS0_ELT = 0x01, /* RFC-2673 (experimental RFC-3363) */
304 | EDNS0_RSVP = 0x3F /* RFC-2671 */
305 | } edns0_label_t;
306 |
307 | typedef uint32_t TTL;
308 |
309 | typedef struct dns_question_t /* RFC-1035 */
310 | {
311 | char const *name;
312 | dns_type_t type;
313 | dns_class_t class;
314 | } dns_question_t;
315 |
316 | typedef struct dns_generic_t /* RFC-1035 */
317 | {
318 | char const *name;
319 | dns_type_t type;
320 | dns_class_t class;
321 | TTL ttl;
322 | } dns_generic_t;
323 |
324 | typedef struct dns_a_t /* RFC-1035 */
325 | {
326 | char const *name;
327 | dns_type_t type;
328 | dns_class_t class;
329 | TTL ttl;
330 | in_addr_t address;
331 | } dns_a_t;
332 |
333 | typedef struct dns_ns_t /* RFC-1035 */
334 | {
335 | char const *name;
336 | dns_type_t type;
337 | dns_class_t class;
338 | TTL ttl;
339 | char const *nsdname;
340 | } dns_ns_t;
341 |
342 | typedef struct dns_md_t /* RFC-1035 */
343 | {
344 | char const *name;
345 | dns_type_t type;
346 | dns_class_t class;
347 | TTL ttl;
348 | char const *madname;
349 | } dns_md_t;
350 |
351 | typedef struct dns_mf_t /* RFC-1035 */
352 | {
353 | char const *name;
354 | dns_type_t type;
355 | dns_class_t class;
356 | TTL ttl;
357 | char const *madname;
358 | } dns_mf_t;
359 |
360 | typedef struct dns_cname_t /* RFC-1035 */
361 | {
362 | char const *name;
363 | dns_type_t type;
364 | dns_class_t class;
365 | TTL ttl;
366 | char const *cname;
367 | } dns_cname_t;
368 |
369 | typedef struct dns_soa_t /* RFC-1035 */
370 | {
371 | char const *name;
372 | dns_type_t type;
373 | dns_class_t class;
374 | TTL ttl;
375 | char const *mname;
376 | char const *rname;
377 | uint32_t serial;
378 | uint32_t refresh;
379 | uint32_t retry;
380 | uint32_t expire;
381 | uint32_t minimum;
382 | } dns_soa_t;
383 |
384 | typedef struct dns_mb_t /* RFC-1035 */
385 | {
386 | char const *name;
387 | dns_type_t type;
388 | dns_class_t class;
389 | TTL ttl;
390 | char const *madname;
391 | } dns_mb_t;
392 |
393 | typedef struct dns_mg_t /* RFC-1035 */
394 | {
395 | char const *name;
396 | dns_type_t type;
397 | dns_class_t class;
398 | TTL ttl;
399 | char const *mgmname;
400 | } dns_mg_t;
401 |
402 | typedef struct dns_mr_t /* RFC-1035 */
403 | {
404 | char const *name;
405 | dns_type_t type;
406 | dns_class_t class;
407 | TTL ttl;
408 | char const *newname;
409 | } dns_mr_t;
410 |
411 | typedef struct dns_null_t /* RFC-1035 */
412 | {
413 | char const *name;
414 | dns_type_t type;
415 | dns_class_t class;
416 | TTL ttl;
417 | size_t size;
418 | uint8_t *data;
419 | } dns_null_t;
420 |
421 | typedef struct dns_wks_t /* RFC-1035 */
422 | {
423 | char const *name;
424 | dns_type_t type;
425 | dns_class_t class;
426 | TTL ttl;
427 | in_addr_t address;
428 | int protocol;
429 | size_t numbits; /* <= 8192 */
430 | uint8_t *bits;
431 | } dns_wks_t;
432 |
433 | typedef struct dns_ptr_t /* RFC-1035 */
434 | {
435 | char const *name;
436 | dns_type_t type;
437 | dns_class_t class;
438 | TTL ttl;
439 | char const *ptr;
440 | } dns_ptr_t;
441 |
442 | typedef struct dns_hinfo_t /* RFC-1035 */
443 | {
444 | char const *name;
445 | dns_type_t type;
446 | dns_class_t class;
447 | TTL ttl;
448 | char const *cpu;
449 | char const *os;
450 | } dns_hinfo_t;
451 |
452 | typedef struct dns_minfo_t /* RFC-1035 */
453 | {
454 | char const *name;
455 | dns_type_t type;
456 | dns_class_t class;
457 | TTL ttl;
458 | char const *rmailbx;
459 | char const *emailbx;
460 | } dns_minfo_t;
461 |
462 | typedef struct dns_mx_t /* RFC-1035 */
463 | {
464 | char const *name;
465 | dns_type_t type;
466 | dns_class_t class;
467 | TTL ttl;
468 | int preference;
469 | char const *exchange;
470 | } dns_mx_t;
471 |
472 | typedef struct dns_txt_t /* RFC-1035 */
473 | {
474 | char const *name;
475 | dns_type_t type;
476 | dns_class_t class;
477 | TTL ttl;
478 | size_t len;
479 | char const *text;
480 | } dns_txt_t;
481 |
482 | typedef struct dns_rp_t /* RFC-1183 */
483 | {
484 | char const *name;
485 | dns_type_t type;
486 | dns_class_t class;
487 | TTL ttl;
488 | char const *mbox;
489 | char const *domain;
490 | } dns_rp_t;
491 |
492 | typedef struct dns_afsdb_t /* RFC-1183 */
493 | {
494 | char const *name;
495 | dns_type_t type;
496 | dns_class_t class;
497 | TTL ttl;
498 | int subtype;
499 | char const *hostname;
500 | } dns_afsdb_t;
501 |
502 | typedef struct dns_x25_t /* RFC-1183 */
503 | {
504 | char const *name;
505 | dns_type_t type;
506 | dns_class_t class;
507 | TTL ttl;
508 | size_t size;
509 | char const *psdnaddress;
510 | } dns_x25_t;
511 |
512 | typedef struct dns_isdn_t /* RFC-1183 */
513 | {
514 | char const *name;
515 | dns_type_t type;
516 | dns_class_t class;
517 | TTL ttl;
518 | char const *isdnaddress;
519 | char const *sa;
520 | } dns_isdn_t;
521 |
522 | typedef struct dns_rt_t /* RFC-1183 */
523 | {
524 | char const *name;
525 | dns_type_t type;
526 | dns_class_t class;
527 | TTL ttl;
528 | int preference;
529 | char const *host;
530 | } dns_rt_t;
531 |
532 | typedef struct dns_nsap_t /* RFC-1348 */
533 | {
534 | char const *name;
535 | dns_type_t type;
536 | dns_class_t class;
537 | TTL ttl;
538 | char const *length;
539 | char const *nsapaddress;
540 | } dns_nsap_t;
541 |
542 | typedef struct dns_nsap_ptr_t /* RFC-1348 */
543 | {
544 | char const *name;
545 | dns_type_t type;
546 | dns_class_t class;
547 | TTL ttl;
548 | char const *owner;
549 | } dns_nsap_ptr_t;
550 |
551 | typedef enum dnskey_algorithm /* RFC-2065 */
552 | {
553 | DNSKEYA_RSAMD5 = 1,
554 | DNSKEYA_DH = 2, /* RFC-2535 */
555 | DNSKEYA_DSA = 3, /* RFC-2535 */
556 | DNSKEYA_ECC = 4, /* RFC-2535 */
557 | DNSKEYA_RSASHA1 = 5, /* RFC-3110 */
558 | DNSKEYA_INDIRECT = 252, /* RFC-2535 */
559 | DNSKEYA_PRIVATEDNS = 253,
560 | DNSKEYA_PRIVATEOID = 254,
561 | DNSKEYA_RSVP = 255
562 | } dnskey_algorithm;
563 |
564 | typedef struct dns_sig_t /* RFC-2065 */
565 | {
566 | char const *name;
567 | dns_type_t type;
568 | dns_class_t class;
569 | TTL ttl;
570 | dns_type_t covered;
571 | dnskey_algorithm algorithm;
572 | int labels;
573 | TTL originttl;
574 | unsigned long sigexpire;
575 | unsigned long timesigned;
576 | uint16_t keyfootprint;
577 | char const *signer;
578 | size_t sigsize;
579 | uint8_t *signature;
580 | } dns_sig_t;
581 |
582 | typedef enum dnskey_protocol /* RFC-2535 */
583 | {
584 | DNSKEYP_NONE = 0,
585 | DNSKEYP_TLS = 1,
586 | DNSKEYP_EMAIL = 2,
587 | DNSKEYP_DNSSEC = 3,
588 | DNSKEYP_IPSEC = 4,
589 | DNSKEYP_ALL = 255
590 | } dnskey_protocol;
591 |
592 | typedef union dnskey_key /* RFC-2065 */
593 | {
594 | struct
595 | {
596 | size_t expsize;
597 | uint8_t *exponent;
598 | size_t modsize;
599 | uint8_t *modulus;
600 | } md5;
601 |
602 | struct
603 | {
604 | size_t size;
605 | uint8_t *data;
606 | } unknown;
607 | } dnskey_key;
608 |
609 | typedef struct dns_key_t /* RFC-2065 */
610 | {
611 | char const *name;
612 | dns_type_t type;
613 | dns_class_t class;
614 | TTL ttl;
615 | struct
616 | {
617 | bool authentication;
618 | bool confidential;
619 | bool experimental;
620 | bool user;
621 | bool zone;
622 | bool host;
623 | bool ipsec;
624 | bool email; /* not in RFC-2535 */
625 | } flags;
626 | int signatory;
627 | dnskey_protocol protocol;
628 | dnskey_algorithm algorithm;
629 | dnskey_key key;
630 | } dns_key_t;
631 |
632 | typedef struct dns_px_t /* RFC-2163 */
633 | {
634 | char const *name;
635 | dns_type_t type;
636 | dns_class_t class;
637 | TTL ttl;
638 | char const *map822;
639 | char const *mapx400;
640 | } dns_px_t;
641 |
642 | typedef struct dnsgpos_angle /* RFC-1712 , RFC1876 */
643 | {
644 | int deg;
645 | int min;
646 | int sec;
647 | int frac;
648 | bool nw; /* Northern or Western Hemisphere */
649 | } dnsgpos_angle;
650 |
651 | typedef struct dns_gpos_t /* RFC-1712 */
652 | {
653 | char const *name;
654 | dns_type_t type;
655 | dns_class_t class;
656 | TTL ttl;
657 | dnsgpos_angle longitude;
658 | dnsgpos_angle latitude;
659 | double altitude;
660 | } dns_gpos_t;
661 |
662 | typedef struct dns_aaaa_t /* RFC-1886 */
663 | {
664 | char const *name;
665 | dns_type_t type;
666 | dns_class_t class;
667 | TTL ttl;
668 | struct in6_addr address;
669 | } dns_aaaa_t;
670 |
671 | typedef struct dns_loc_t /* RFC-1876 */
672 | {
673 | char const *name;
674 | dns_type_t type;
675 | dns_class_t class;
676 | TTL ttl;
677 | int version;
678 | unsigned long long size; /* plese see RFC-1876 for a discussion */
679 | unsigned long long horiz_pre; /* of these fields */
680 | unsigned long long vert_pre;
681 | dnsgpos_angle latitude;
682 | dnsgpos_angle longitude;
683 | long altitude;
684 | } dns_loc_t;
685 |
686 | typedef struct dns_nxt_t /* RFC-2065 */
687 | {
688 | char const *name;
689 | dns_type_t type;
690 | dns_class_t class;
691 | TTL ttl;
692 | char const *next;
693 | size_t numbits;
694 | uint8_t *bitmap;
695 | } dns_nxt_t;
696 |
697 | typedef struct dns_eid_t /* (unknown) */
698 | {
699 | char const *name;
700 | dns_type_t type;
701 | dns_class_t class;
702 | TTL ttl;
703 | size_t size;
704 | uint8_t *rawdata;
705 | } dns_eid_t;
706 |
707 | typedef struct dns_nimloc_t /* (unknown) */
708 | {
709 | char const *name;
710 | dns_type_t type;
711 | dns_class_t class;
712 | TTL ttl;
713 | size_t size;
714 | uint8_t *rawdata;
715 | } dns_nimloc_t;
716 |
717 | typedef struct dns_srv_t /* RFC-2782 */
718 | {
719 | char const *name;
720 | dns_type_t type;
721 | dns_class_t class;
722 | TTL ttl;
723 | int priority;
724 | int weight;
725 | int port;
726 | char const *target;
727 | } dns_srv_t;
728 |
729 | typedef struct dns_atm_t /* (unknown) */
730 | {
731 | char const *name;
732 | dns_type_t type;
733 | dns_class_t class;
734 | TTL ttl;
735 | size_t size;
736 | uint8_t *rawdata;
737 | } dns_atm_t;
738 |
739 | typedef struct dns_naptr_t /* RFC-2915 */
740 | {
741 | char const *name;
742 | dns_type_t type;
743 | dns_class_t class;
744 | TTL ttl;
745 | int order;
746 | int preference;
747 | char const *flags;
748 | char const *services;
749 | char const *regexp;
750 | char const *replacement;
751 | } dns_naptr_t;
752 |
753 | typedef struct dns_kx_t /* (unknown) */
754 | {
755 | char const *name;
756 | dns_type_t type;
757 | dns_class_t class;
758 | TTL ttl;
759 | size_t size;
760 | uint8_t *rawdata;
761 | } dns_kx_t;
762 |
763 | typedef struct dns_cert_t /* (unknown) */
764 | {
765 | char const *name;
766 | dns_type_t type;
767 | dns_class_t class;
768 | TTL ttl;
769 | size_t size;
770 | uint8_t *rawdata;
771 | } dns_cert_t;
772 |
773 | typedef struct dns_a6_t /* RFC-2874 */
774 | {
775 | char const *name;
776 | dns_type_t type;
777 | dns_class_t class;
778 | TTL ttl;
779 | size_t mask;
780 | struct in6_addr address;
781 | char const *prefixname;
782 | } dns_a6_t;
783 |
784 | typedef struct dns_dname_t /* RFC-2672 */
785 | {
786 | char const *name;
787 | dns_type_t type;
788 | dns_class_t class;
789 | TTL ttl;
790 | size_t size;
791 | uint8_t *rawdata;
792 | } dns_dname_t;
793 |
794 | typedef struct dns_sink_t /* (unknown) */
795 | {
796 | char const *name;
797 | dns_type_t type;
798 | dns_class_t class;
799 | TTL ttl;
800 | size_t size;
801 | uint8_t *rawdata;
802 | } dns_sink_t;
803 |
804 | typedef struct edns0_opt_t /* RFC-2671 */
805 | {
806 | edns0_type_t code; /* 0 <= code <= UINT16_MAX */
807 | size_t len; /* 0 <= len <= UINT16_MAX */
808 | uint8_t *data; /* encoded per RFC specification */
809 | } edns0_opt_t;
810 |
811 | typedef struct dns_edns0opt_t /* RFC-2671 */
812 | {
813 | char const *name;
814 | dns_type_t type;
815 | dns_class_t class; /* not applicable --- set to CLASS_UNKNOWN */
816 | TTL ttl; /* not applicable --- set to 0 */
817 | size_t udp_payload;
818 | int version;
819 | bool fdo; /* RFC-3225 */
820 | int fug;
821 | unsigned int z; /* should be zero */
822 | size_t numopts;
823 | edns0_opt_t *opts;
824 | } dns_edns0opt_t;
825 |
826 | typedef struct dnsapl_record /* RFC-3123 */
827 | {
828 | int addressfamily;
829 | int prefix;
830 | size_t afdlength;
831 | uint8_t *afdpart;
832 | bool negate;
833 | } dnsapl_record;
834 |
835 | typedef struct dns_apl_t /* RFC-3123 */
836 | {
837 | char const *name;
838 | dns_type_t type;
839 | dns_class_t class;
840 | TTL ttl;
841 | size_t numrecs;
842 | dnsapl_record *recs;
843 | } dns_apl_t;
844 |
845 |
846 | typedef enum dnsds_digest /* RFC-3658 */
847 | {
848 | DNSDS_SHA1 = 1
849 | } dnsds_digest;
850 |
851 | typedef struct dns_ds_t /* RFC-3658 */
852 | {
853 | char const *name;
854 | dns_type_t type;
855 | dns_class_t class;
856 | TTL ttl;
857 | dnskey_protocol keytag;
858 | dnskey_algorithm algorithm;
859 | dnsds_digest digest;
860 | size_t digestlen;
861 | uint8_t *digestdata;
862 | } dns_ds_t;
863 |
864 | typedef struct dns_rrsig_t /* RFC-4034 */
865 | {
866 | char const *name;
867 | dns_type_t type;
868 | dns_class_t class;
869 | TTL ttl;
870 | dns_type_t covered;
871 | dnskey_algorithm algorithm;
872 | int labels;
873 | TTL originttl;
874 | unsigned long sigexpire;
875 | unsigned long timesigned;
876 | uint16_t keyfootprint;
877 | char const *signer;
878 | size_t sigsize;
879 | uint8_t *signature;
880 | } dns_rrsig_t;
881 |
882 | typedef struct dns_nsec_t /* RFC-4034 */
883 | {
884 | char const *name;
885 | dns_type_t type;
886 | dns_class_t class;
887 | TTL ttl;
888 | char const *next;
889 | size_t numbits;
890 | uint8_t *bitmap;
891 | } dns_nsec_t;
892 |
893 | typedef struct dns_dnskey_t /* RFC-4034 */
894 | {
895 | char const *name;
896 | dns_type_t type;
897 | dns_class_t class;
898 | TTL ttl;
899 | bool zonekey;
900 | bool sep;
901 | dnskey_protocol protocol; /* must be DNSKEYP_DNSSEC */
902 | dnskey_algorithm algorithm;
903 | size_t keysize;
904 | uint8_t *key;
905 | } dns_dnskey_t;
906 |
907 | typedef struct dns_sshfp_t /* RFC-4255 */
908 | {
909 | char const *name;
910 | dns_type_t type;
911 | dns_class_t class;
912 | TTL ttl;
913 | dnskey_algorithm algorithm;
914 | dnsds_digest fptype;
915 | size_t fpsize;
916 | uint8_t *fingerprint;
917 | } dns_sshfp_t;
918 |
919 | typedef struct dns_spf_t /* RFC-4408 */
920 | {
921 | char const *name;
922 | dns_type_t type;
923 | dns_class_t class;
924 | TTL ttl;
925 | size_t len;
926 | char const *text;
927 | } dns_spf_t;
928 |
929 | typedef struct dns_tsig_t /* RFC-2845 */
930 | {
931 | char const *name;
932 | dns_type_t type;
933 | dns_class_t class;
934 | TTL ttl; /* must be 0 */
935 | char const *algorithm;
936 | uint64_t timesigned;
937 | unsigned int fudge;
938 | size_t MACsize;
939 | uint8_t *MAC;
940 | int id;
941 | int error;
942 | size_t lenother;
943 | uint8_t *other;
944 | } dns_tsig_t;
945 |
946 | typedef struct dns_x_t /* CATCH-ALL */
947 | {
948 | char const *name;
949 | dns_type_t type;
950 | dns_class_t class;
951 | TTL ttl;
952 | size_t size;
953 | uint8_t *rawdata;
954 | } dns_x_t;
955 |
956 | typedef union dns_answer_t
957 | {
958 | dns_generic_t generic;
959 | dns_x_t x;
960 | dns_a_t a;
961 | dns_ns_t ns;
962 | dns_md_t md;
963 | dns_mf_t mf;
964 | dns_cname_t cname;
965 | dns_soa_t soa;
966 | dns_mb_t mb;
967 | dns_mg_t mg;
968 | dns_mr_t mr;
969 | dns_null_t null;
970 | dns_wks_t wks;
971 | dns_ptr_t ptr;
972 | dns_hinfo_t hinfo;
973 | dns_minfo_t minfo;
974 | dns_mx_t mx;
975 | dns_txt_t txt;
976 | dns_rp_t rp;
977 | dns_afsdb_t afsdb;
978 | dns_x25_t x25;
979 | dns_isdn_t isdn;
980 | dns_rt_t rt;
981 | dns_nsap_t nsap;
982 | dns_nsap_ptr_t nsap_ptr;
983 | dns_sig_t sig;
984 | dns_key_t key;
985 | dns_px_t px;
986 | dns_gpos_t gpos;
987 | dns_aaaa_t aaaa;
988 | dns_loc_t loc;
989 | dns_nxt_t nxt;
990 | dns_eid_t eid;
991 | dns_nimloc_t nimloc;
992 | dns_srv_t srv;
993 | dns_atm_t atm;
994 | dns_naptr_t naptr;
995 | dns_kx_t kx;
996 | dns_cert_t cert;
997 | dns_a6_t a6;
998 | dns_dname_t dname;
999 | dns_sink_t sink;
1000 | dns_edns0opt_t opt;
1001 | dns_apl_t apl;
1002 | dns_ds_t ds;
1003 | dns_rrsig_t rrsig;
1004 | dns_nsec_t nsec;
1005 | dns_dnskey_t dnskey;
1006 | dns_spf_t spf;
1007 | dns_tsig_t tsig;
1008 | } dns_answer_t;
1009 |
1010 | typedef struct dns_query_t /* RFC-1035 */
1011 | {
1012 | int id;
1013 | bool query;
1014 | dns_op_t opcode;
1015 | bool aa;
1016 | bool tc;
1017 | bool rd;
1018 | bool ra;
1019 | bool z; /* should be zero */
1020 | bool ad; /* RFC-2065 */
1021 | bool cd; /* RFC-2065 */
1022 | dns_rcode_t rcode;
1023 | size_t qdcount;
1024 | size_t ancount;
1025 | size_t nscount;
1026 | size_t arcount;
1027 | dns_question_t *questions;
1028 | dns_answer_t *answers;
1029 | dns_answer_t *nameservers;
1030 | dns_answer_t *additional;
1031 | } dns_query_t;
1032 |
1033 | /**********************************************************************/
1034 |
1035 | extern dns_rcode_t dns_encode(dns_packet_t *,size_t *,const dns_query_t *) __attribute__ ((nothrow,nonnull));
1036 | extern dns_rcode_t dns_decode(dns_decoded_t *,size_t *,const dns_packet_t *,size_t) __attribute__ ((nothrow,nonnull(1,2,3)));
1037 |
1038 | #ifdef __cplusplus
1039 | }
1040 | # undef class
1041 | # undef restrict
1042 | #endif
1043 | #endif
1044 |
--------------------------------------------------------------------------------
/src/dotest.c:
--------------------------------------------------------------------------------
1 | /*************************************************************************
2 | *
3 | * Copyright 2010 by Sean Conner. All Rights Reserved.
4 | *
5 | * This library is free software; you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published by
7 | * the Free Software Foundation; either version 3 of the License, or (at your
8 | * option) any later version.
9 | *
10 | * This library is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
13 | * License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this library; if not, see .
17 | *
18 | **************************************************************************/
19 |
20 | /**********************************************************************
21 | *
22 | * Sample application using my DNS library. It's somewhat similar to dig,
23 | * but lacking features found in dig. Still useful though, and gives an
24 | * example of how to use the DNS library.
25 | *
26 | * This code is C99.
27 | *
28 | ***************************************************************************/
29 |
30 | #include
31 | #include
32 | #include
33 |
34 | #include
35 |
36 | #include "dns.h"
37 | #include "mappings.h"
38 | #include "netsimple.h"
39 | #include "output.h"
40 |
41 | enum
42 | {
43 | OPT_NONE = '\0',
44 | OPT_HELP = 'h',
45 | OPT_EDNS = 'e',
46 | OPT_SERVER = 's',
47 | OPT_DUMP = 'd',
48 | OPT_ERR = '?'
49 | };
50 |
51 | /************************************************************************/
52 |
53 | static void usage (const char *);
54 |
55 | /************************************************************************/
56 |
57 | const struct option c_options[] =
58 | {
59 | { "server" , required_argument , NULL , OPT_SERVER } ,
60 | { "edns" , no_argument , NULL , OPT_EDNS } ,
61 | { "dump" , no_argument , NULL , OPT_DUMP } ,
62 | { "help" , no_argument , NULL , OPT_HELP } ,
63 | { NULL , 0 , NULL , 0 }
64 | };
65 |
66 | /***********************************************************************/
67 |
68 | int main(int argc,char *argv[])
69 | {
70 | const char *serverhost;
71 | const char *host;
72 | const char *type;
73 | bool fdump;
74 | bool fedns;
75 | int option;
76 | int rc;
77 |
78 | /*-------------------------------------------------------------------------
79 | ; verbiage to parse the command line and set some sane defaults, yada yada
80 | ; blah blah blah
81 | ;------------------------------------------------------------------*/
82 |
83 | serverhost = "127.0.0.1";
84 | host = "example.net";
85 | type = "A";
86 | fdump = false;
87 | fedns = false;
88 | option = 0;
89 | opterr = 0; /* prevent getopt_long() from printing error messages */
90 |
91 | while(true)
92 | {
93 | rc = getopt_long(argc,argv,"hdes:",c_options,&option);
94 | if (rc == EOF) break;
95 |
96 | switch(rc)
97 | {
98 | default:
99 | case OPT_ERR:
100 | fprintf(stderr,"unknown option '%c'\n",optopt);
101 | case OPT_HELP:
102 | usage(argv[0]);
103 | return EXIT_FAILURE;
104 | case OPT_SERVER:
105 | serverhost = optarg;
106 | break;
107 | case OPT_EDNS:
108 | fedns = true;
109 | break;
110 | case OPT_DUMP:
111 | fdump = true;
112 | break;
113 | case OPT_NONE:
114 | break;
115 | }
116 | }
117 |
118 | if (optind == argc)
119 | {
120 | usage(argv[0]);
121 | return EXIT_FAILURE;
122 | }
123 |
124 | host = argv[optind++];
125 |
126 | if (optind < argc)
127 | type = argv[optind];
128 |
129 | /*------------------------------------------------------------------------
130 | ; Encoding of a DNS query. I'm finding that many (if not all) DNS servers
131 | ; only accept a single question, even though the protocol seems to allow
132 | ; more than one question. If there *is* a DNS server that can handle
133 | ; multiple questions, then we can handle them, even if they don't exist
134 | ; yet.
135 | ;--------------------------------------------------------------------*/
136 |
137 | dns_question_t domain;
138 | dns_query_t query;
139 | dns_packet_t request[DNS_BUFFER_UDP];
140 | size_t reqsize;
141 | edns0_opt_t opt;
142 | dns_answer_t edns;
143 |
144 | domain.name = host;
145 | domain.type = dns_type_value(type);
146 | domain.class = CLASS_IN;
147 |
148 | query.id = 1234; /* should be a random value */
149 | query.query = true;
150 | query.opcode = OP_QUERY;
151 | query.aa = false;
152 | query.tc = false;
153 | query.rd = true;
154 | query.ra = false;
155 | query.z = false;
156 | query.ad = false;
157 | query.cd = false;
158 | query.rcode = RCODE_OKAY;
159 | query.qdcount = 1;
160 | query.questions = &domain;
161 | query.ancount = 0;
162 | query.answers = NULL;
163 | query.nscount = 0;
164 | query.nameservers = NULL;
165 | query.arcount = 0;
166 | query.additional = NULL;
167 |
168 | if (fedns)
169 | {
170 | /*----------------------------------------------------------------------
171 | ; Test EDNS0 by sending an NSID OPT RR type query.
172 | ;
173 | ; The udp_payload is the largest UDP packet we can reasonably expect to
174 | ; receive. I'm using the value 1464 since that's about the largest UDP
175 | ; packet that can fit into an Ethernet frame (20 bytes IP header, 8
176 | ; bytes UDP header; RFC-1042 based Ethernet frame).
177 | ;
178 | ; Additionally, OPT RRs *MUST* be in the additional section of a DNS
179 | ; packet, and there can be only one (Highlander 2 & 3? Never happened;
180 | ; neither did the TV series) OPT RR.
181 | ;----------------------------------------------------------------------*/
182 |
183 | opt.code = EDNS0RR_NSID;
184 | opt.data = (uint8_t *)"MY-DNS-SERVER-ID";
185 | opt.len = strlen((char *)opt.data);
186 |
187 | edns.opt.name = ".";
188 | edns.opt.type = RR_OPT;
189 | edns.opt.class = CLASS_UNKNOWN;
190 | edns.opt.ttl = 0;
191 | edns.opt.udp_payload = 1464;
192 | edns.opt.version = 0;
193 | edns.opt.fdo = false;
194 | edns.opt.z = 0;
195 | edns.opt.numopts = 1;
196 | edns.opt.opts = &opt;
197 |
198 | query.arcount = 1;
199 | query.additional = &edns;
200 | }
201 |
202 | reqsize = sizeof(request);
203 | rc = dns_encode(request,&reqsize,&query);
204 | if (rc != RCODE_OKAY)
205 | {
206 | fprintf(stderr,"dns_encode() = (%d) %s\n",rc,dns_rcode_text(rc));
207 | return EXIT_FAILURE;
208 | }
209 |
210 | if (fdump)
211 | {
212 | printf("OUTGOING:\n\n");
213 | dns_dump_memory(stdout,request,reqsize,0);
214 | }
215 |
216 | /*-----------------------------------------------------------------------
217 | ; Sending a DNS query. This uses the simple interface provided and is
218 | ; not good for much *except* as an example. If you have any complex
219 | ; requirements, do not look to this code.
220 | ;-----------------------------------------------------------------------*/
221 |
222 | sockaddr_all server;
223 | dns_packet_t reply[DNS_BUFFER_UDP];
224 | size_t replysize;
225 |
226 | rc = net_server(&server,serverhost);
227 | if (rc != 0)
228 | {
229 | fprintf(stderr,"net_server() = %s",strerror(rc));
230 | return EXIT_FAILURE;
231 | }
232 |
233 | replysize = sizeof(reply);
234 | rc = net_request(&server,reply,&replysize,request,reqsize);
235 | if (rc != 0)
236 | {
237 | fprintf(stderr,"net_request() = %s\n",strerror(rc));
238 | return EXIT_FAILURE;
239 | }
240 |
241 | if (fdump)
242 | {
243 | printf("\nINCOMING:\n\n");
244 | dns_dump_memory(stdout,reply,replysize,0);
245 | }
246 |
247 | /*----------------------------------------------------------------------
248 | ; Decode a DNS packet into something we can use. dns_decoded_t is a type
249 | ; to ensure proper alignment for stack based results---this must be big
250 | ; enough to handle not only the dns_query_t but additional information as
251 | ; well. The 4K size so far seems good enough for decoding UDP packets,
252 | ; although I'm using the 8K size just in case.
253 | ;-----------------------------------------------------------------------*/
254 |
255 | dns_decoded_t bufresult[DNS_DECODEBUF_8K];
256 | size_t bufsize;
257 |
258 | bufsize = sizeof(bufresult);
259 | rc = dns_decode(bufresult,&bufsize,reply,replysize);
260 | if (rc != RCODE_OKAY)
261 | {
262 | fprintf(stderr,"dns_decode() = (%d) %s\n",rc,dns_rcode_text(rc));
263 | return EXIT_FAILURE;
264 | }
265 |
266 | if (fdump)
267 | printf("\nBytes used: %lu\n\n",(unsigned long)bufsize);
268 |
269 | /*----------------------------------------
270 | ; see the code in output.c
271 | ;-----------------------------------------*/
272 |
273 | dns_print_result((dns_query_t *)bufresult);
274 | return EXIT_SUCCESS;
275 | }
276 |
277 | /*********************************************************************/
278 |
279 | static void usage(const char *prog)
280 | {
281 | assert(prog != NULL);
282 |
283 | fprintf(
284 | stderr,
285 | "usage: %s [-h] [-d] [-e] [-s server] host [type]\n"
286 | "\t-h\t\tusage text (this text)\n"
287 | "\t-d\t\tdump raw DNS queries\n"
288 | "\t-e\t\tInclude EDNS0 RR with query\n"
289 | "\t-s server\tIP address of server\n"
290 | "\n"
291 | "\ttype\t\tRR DNS type\n",
292 | prog
293 | );
294 | }
295 |
296 | /**********************************************************************/
297 |
--------------------------------------------------------------------------------
/src/luadns.c:
--------------------------------------------------------------------------------
1 | /*************************************************************************
2 | *
3 | * Copyright 2010 by Sean Conner. All Rights Reserved.
4 | *
5 | * This library is free software; you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published by
7 | * the Free Software Foundation; either version 3 of the License, or (at your
8 | * option) any later version.
9 | *
10 | * This library is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
13 | * License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this library; if not, see .
17 | *
18 | **************************************************************************/
19 |
20 | /**********************************************************************
21 | *
22 | * Implements Lua bindings for my DNS library. This exports four functions
23 | * in the org.conman.dns object:
24 | *
25 | * encode(t)
26 | *
27 | * Accepts a table in the form:
28 | *
29 | * {
30 | * id = some_number,
31 | * query = true, -- making a query
32 | * rd = true, -- for recursive queries
33 | * opcode = 'query',
34 | * question = {
35 | * name = 'www.example.com',
36 | * type = 'loc',
37 | * class = 'in'
38 | * }, -- and optionally
39 | * additional = {
40 | * name = '.',
41 | * type = 'opt',
42 | * udp_payload = 1464,
43 | * version = 0,
44 | * fdo = false,
45 | * opts = {
46 | * {
47 | * type = 'nsid', -- or a number
48 | * data = "..."
49 | * } -- and more, if required
50 | * }
51 | * }
52 | * }
53 | *
54 | * And returns a binary string that is the wire format of the
55 | * query. This binary string can then be sent over a UDP or
56 | * TCP packet to a DNS server.
57 | *
58 | * This returns a binary string on success, nil,rcode on
59 | * failre.
60 | *
61 | * See lua/test.lua for an example of using this function.
62 | *
63 | * decode(bs)
64 | *
65 | * Decodes a binary string into a table (similar to the table
66 | * above) for easy use of the DNS response.
67 | *
68 | * This returns a table on success, or nil,rcode on failure.
69 | *
70 | * See lua/test.lua for an example of using this function.
71 | *
72 | * query(server,bs)
73 | *
74 | * Sends the encoded binary string to the given server. The
75 | * server variable is a string of the IP address (IPv4 or
76 | * IPv6)---hostnames will fail.
77 | *
78 | * This function is very stupid simple; it sends the request,
79 | * and if it doesn't see a reply in 15 seconds, it returns a
80 | * failure. No restransmission of the packet is done. This is
81 | * probably fine for simple applications but not for anything
82 | * heavy duty or rubust.
83 | *
84 | * This returns a binary string of the reponse, or nil,rcode on
85 | * failure.
86 | *
87 | * strerror(rcode)
88 | *
89 | * Returns a string representation of the server response, or
90 | * the return value from a failed query() call. This function
91 | * does not fail (if it does, there's more to worry about).
92 | *
93 | *
94 | * This code is written to C99.
95 | *
96 | ***************************************************************************/
97 |
98 | #include
99 | #include
100 | #include
101 | #include
102 |
103 | #include
104 | #include
105 |
106 | #include "dns.h"
107 | #include "mappings.h"
108 | #include "netsimple.h"
109 |
110 | /********************************************************************/
111 |
112 | #if LUA_VERSION_NUM == 501
113 | # define lua_rawlen(L,i) lua_objlen((L),(i))
114 | static int lua_absindex(lua_State *L,int idx)
115 | {
116 | return (idx > 0) || (idx < LUA_REGISTRYINDEX)
117 | ? idx
118 | : lua_gettop(L) + idx + 1
119 | ;
120 | }
121 | #endif
122 |
123 | /********************************************************************/
124 |
125 | static void to_question(lua_State *L,dns_question_t **pq,size_t *pqs,int idx)
126 | {
127 | assert(L != NULL);
128 | assert(pq != NULL);
129 | assert(pqs != NULL);
130 | assert(idx != 0);
131 |
132 | /*----------------------------------------------------------------------
133 | ; while dns_encode() supports more than one question, most servers today
134 | ; (2021) *still* do not support more than one question, and most of the
135 | ; existing Lua code assumes one question. So let's keep with tradition
136 | ; for now.
137 | ;-----------------------------------------------------------------------*/
138 |
139 | idx = lua_absindex(L,idx);
140 | *pqs = 1;
141 | *pq = lua_newuserdata(L,*pqs * sizeof(dns_question_t));
142 |
143 | lua_getfield(L,idx,"name");
144 | lua_getfield(L,idx,"type");
145 | lua_getfield(L,idx,"class");
146 |
147 | (*pq)[0].name = luaL_checkstring(L,-3);
148 | (*pq)[0].type = dns_type_value(luaL_optstring(L,-2,"A"));
149 | (*pq)[0].class = dns_class_value(luaL_optstring(L,-1,"IN"));
150 | lua_pop(L,3);
151 | }
152 |
153 | /********************************************************************/
154 |
155 | static void to_dnsgpos_angle(lua_State *L,dnsgpos_angle *ang,int idx,bool lat)
156 | {
157 | lua_Number sec;
158 |
159 | idx = lua_absindex(L,idx);
160 | lua_getfield(L,idx,"deg");
161 | lua_getfield(L,idx,"min");
162 | lua_getfield(L,idx,"sec");
163 |
164 | ang->deg = luaL_checkinteger(L,-3);
165 | ang->min = luaL_checkinteger(L,-2);
166 | ang->frac = modf(luaL_checknumber(L,-1),&sec) * 1000.0;
167 | ang->sec = sec;
168 | lua_pop(L,3);
169 |
170 | lua_getfield(L,idx,"hemisphere");
171 | if (!lua_isnil(L,-1))
172 | {
173 | char const *s = luaL_checkstring(L,-1);
174 | if (lat)
175 | ang->nw = toupper(*s) == 'N';
176 | else
177 | ang->nw = toupper(*s) == 'W';
178 | lua_pop(L,1);
179 | }
180 | else
181 | {
182 | lua_getfield(L,idx,"nw");
183 | ang->nw = lua_toboolean(L,-1);
184 | lua_pop(L,2);
185 | }
186 | }
187 |
188 | /********************************************************************/
189 |
190 | static void to_answers(lua_State *L,dns_answer_t **pa,size_t *pas,int idx)
191 | {
192 | int top;
193 | int tidx;
194 |
195 | assert(L != NULL);
196 | assert(pa != NULL);
197 | assert(pas != NULL);
198 | assert(idx != 0);
199 |
200 | idx = lua_absindex(L,idx);
201 | *pas = lua_rawlen(L,idx);
202 | *pa = lua_newuserdata(L,*pas * sizeof(dns_answer_t));
203 | top = lua_gettop(L);
204 |
205 | for (size_t i = 0 ; i < *pas ; i++)
206 | {
207 | lua_pushinteger(L,i + 1);
208 | lua_gettable(L,idx);
209 | tidx = lua_absindex(L,-1);
210 |
211 | lua_getfield(L,tidx,"name");
212 | lua_getfield(L,tidx,"type");
213 | lua_getfield(L,tidx,"class");
214 | lua_getfield(L,tidx,"ttl");
215 |
216 | (*pa)[i].generic.name = luaL_checkstring(L,-4);
217 | (*pa)[i].generic.type = dns_type_value(luaL_checkstring(L,-3));
218 | (*pa)[i].generic.class = dns_class_value(luaL_optstring(L,-2,"IN"));
219 | (*pa)[i].generic.ttl = luaL_checkinteger(L,-1);
220 |
221 | switch((*pa)[i].generic.type)
222 | {
223 | case RR_A:
224 | lua_getfield(L,tidx,"raw_address");
225 | if (!lua_isnil(L,-1))
226 | {
227 | size_t s;
228 | char const *a = luaL_checklstring(L,-1,&s);
229 | if (s != 4) luaL_error(L,"not an IP address in A record");
230 | memcpy(&(*pa)[i].a.address,a,4);
231 | }
232 | else
233 | {
234 | lua_getfield(L,tidx,"address");
235 | if (inet_pton(AF_INET,luaL_checkstring(L,-1),&(*pa)[i].a.address) != 0)
236 | luaL_error(L,"Not an IP address in A record");
237 | }
238 | break;
239 |
240 | case RR_SOA:
241 | lua_getfield(L,tidx,"mname");
242 | lua_getfield(L,tidx,"rname");
243 | lua_getfield(L,tidx,"serial");
244 | lua_getfield(L,tidx,"refresh");
245 | lua_getfield(L,tidx,"retry");
246 | lua_getfield(L,tidx,"expire");
247 | lua_getfield(L,tidx,"minimum");
248 | (*pa)[i].soa.mname = luaL_checkstring(L,-7);
249 | (*pa)[i].soa.rname = luaL_checkstring(L,-6);
250 | (*pa)[i].soa.serial = luaL_checkinteger(L,-5);
251 | (*pa)[i].soa.refresh = luaL_checkinteger(L,-4);
252 | (*pa)[i].soa.retry = luaL_checkinteger(L,-3);
253 | (*pa)[i].soa.expire = luaL_checkinteger(L,-2);
254 | (*pa)[i].soa.minimum = luaL_checkinteger(L,-1);
255 | break;
256 |
257 | case RR_NAPTR:
258 | lua_getfield(L,tidx,"order");
259 | lua_getfield(L,tidx,"preference");
260 | lua_getfield(L,tidx,"flags");
261 | lua_getfield(L,tidx,"services");
262 | lua_getfield(L,tidx,"regexp");
263 | lua_getfield(L,tidx,"replacement");
264 | (*pa)[i].naptr.order = luaL_checkinteger(L,-6);
265 | (*pa)[i].naptr.preference = luaL_checkinteger(L,-5);
266 | (*pa)[i].naptr.flags = luaL_checkstring(L,-4);
267 | (*pa)[i].naptr.services = luaL_checkstring(L,-3);
268 | (*pa)[i].naptr.regexp = luaL_checkstring(L,-2);
269 | (*pa)[i].naptr.replacement = luaL_checkstring(L,-1);
270 | break;
271 |
272 | case RR_AAAA:
273 | lua_getfield(L,tidx,"raw_address");
274 | if (!lua_isnil(L,-1))
275 | {
276 | size_t s;
277 | char const *a = luaL_checklstring(L,-1,&s);
278 | if (s != 16) luaL_error(L,"not an IPv6 address in AAAA record");
279 | memcpy(&(*pa)[i].aaaa.address,a,16);
280 | }
281 | else
282 | {
283 | lua_getfield(L,tidx,"address");
284 | if (inet_pton(AF_INET6,luaL_checkstring(L,-1),&(*pa)[i].aaaa.address) != 0)
285 | luaL_error(L,"not an IPv6 address in AAAA record");
286 | }
287 | break;
288 |
289 | case RR_SRV:
290 | lua_getfield(L,tidx,"priority");
291 | lua_getfield(L,tidx,"weight");
292 | lua_getfield(L,tidx,"port");
293 | lua_getfield(L,tidx,"target");
294 | (*pa)[i].srv.priority = luaL_checkinteger(L,-4);
295 | (*pa)[i].srv.weight = luaL_checkinteger(L,-3);
296 | (*pa)[i].srv.port = luaL_checkinteger(L,-2);
297 | (*pa)[i].srv.target = luaL_checkstring(L,-1);
298 | break;
299 |
300 | case RR_WKS:
301 | lua_getfield(L,tidx,"raw_address");
302 | if (!lua_isnil(L,-1))
303 | {
304 | size_t s;
305 | char const *a = luaL_checklstring(L,-1,&s);
306 | if (s != 4) luaL_error(L,"not an IP address in A record");
307 | memcpy(&(*pa)[i].wks.address,a,4);
308 | }
309 | else
310 | {
311 | lua_getfield(L,tidx,"address");
312 | if (inet_pton(AF_INET,luaL_checkstring(L,-1),&(*pa)[i].wks.address) != 0)
313 | luaL_error(L,"Not an IP address in A record");
314 | }
315 |
316 | lua_getfield(L,tidx,"protocol");
317 | lua_getfield(L,tidx,"bits");
318 | (*pa)[i].wks.protocol = luaL_checkinteger(L,-1);
319 | (*pa)[i].wks.bits = (uint8_t *)luaL_checklstring(L,-2,&(*pa)[i].wks.numbits);
320 | break;
321 |
322 | case RR_GPOS:
323 | lua_getfield(L,tidx,"longitude");
324 | lua_getfield(L,tidx,"latitude");
325 | lua_getfield(L,tidx,"altitude");
326 | to_dnsgpos_angle(L,&(*pa)[i].gpos.longitude,-3,false);
327 | to_dnsgpos_angle(L,&(*pa)[i].gpos.latitude,-2,true);
328 | (*pa)[i].gpos.altitude = luaL_checknumber(L,-1);
329 | break;
330 |
331 | case RR_LOC:
332 | lua_getfield(L,tidx,"version");
333 | lua_getfield(L,tidx,"size");
334 | lua_getfield(L,tidx,"horiz_pre");
335 | lua_getfield(L,tidx,"vert_pre");
336 | lua_getfield(L,tidx,"latitude");
337 | lua_getfield(L,tidx,"longitude");
338 | lua_getfield(L,tidx,"altitude");
339 | (*pa)[i].loc.version = luaL_optinteger(L,-7,0);
340 | (*pa)[i].loc.size = luaL_checkinteger(L,-6);
341 | (*pa)[i].loc.horiz_pre = luaL_checkinteger(L,-5);
342 | (*pa)[i].loc.vert_pre = luaL_checkinteger(L,-4);
343 | to_dnsgpos_angle(L,&(*pa)[i].loc.latitude,-3,true);
344 | to_dnsgpos_angle(L,&(*pa)[i].loc.longitude,-2,false);
345 | (*pa)[i].loc.altitude = luaL_checkinteger(L,-1);
346 | break;
347 |
348 | case RR_PX:
349 | lua_getfield(L,tidx,"map822");
350 | lua_getfield(L,tidx,"mapx400");
351 | (*pa)[i].px.map822 = luaL_checkstring(L,-2);
352 | (*pa)[i].px.mapx400 = luaL_checkstring(L,-1);
353 | break;
354 |
355 | case RR_RP:
356 | lua_getfield(L,tidx,"mbox");
357 | lua_getfield(L,tidx,"domain");
358 | (*pa)[i].rp.mbox = luaL_checkstring(L,-2);
359 | (*pa)[i].rp.domain = luaL_checkstring(L,-1);
360 | break;
361 |
362 | case RR_MINFO:
363 | lua_getfield(L,tidx,"rmailbx");
364 | lua_getfield(L,tidx,"emailbx");
365 | (*pa)[i].minfo.rmailbx = luaL_checkstring(L,-2);
366 | (*pa)[i].minfo.emailbx = luaL_checkstring(L,-1);
367 | break;
368 |
369 | case RR_AFSDB:
370 | lua_getfield(L,tidx,"subtype");
371 | lua_getfield(L,tidx,"hostname");
372 | (*pa)[i].afsdb.subtype = luaL_checkinteger(L,-2);
373 | (*pa)[i].afsdb.hostname = luaL_checkstring(L,-1);
374 | break;
375 |
376 | case RR_RT:
377 | lua_getfield(L,tidx,"preference");
378 | lua_getfield(L,tidx,"host");
379 | (*pa)[i].rt.preference = luaL_checkinteger(L,-2);
380 | (*pa)[i].rt.host = luaL_checkstring(L,-1);
381 | break;
382 |
383 | case RR_MX:
384 | lua_getfield(L,tidx,"preference");
385 | lua_getfield(L,tidx,"exchange");
386 | (*pa)[i].mx.preference = luaL_checkinteger(L,-2);
387 | (*pa)[i].mx.exchange = luaL_checkstring(L,-1);
388 | break;
389 |
390 | case RR_NSAP:
391 | lua_getfield(L,tidx,"length");
392 | lua_getfield(L,tidx,"address");
393 | (*pa)[i].nsap.length = luaL_checkstring(L,-2);
394 | (*pa)[i].nsap.nsapaddress = luaL_checkstring(L,-1);
395 | break;
396 |
397 | case RR_ISDN:
398 | lua_getfield(L,tidx,"address");
399 | lua_getfield(L,tidx,"sa");
400 | (*pa)[i].isdn.isdnaddress = luaL_checkstring(L,-2);
401 | (*pa)[i].isdn.sa = luaL_checkstring(L,-1);
402 | break;
403 |
404 | case RR_HINFO:
405 | lua_getfield(L,tidx,"cpu");
406 | lua_getfield(L,tidx,"os");
407 | (*pa)[i].hinfo.cpu = luaL_checkstring(L,-2);
408 | (*pa)[i].hinfo.os = luaL_checkstring(L,-1);
409 | break;
410 |
411 | case RR_X25:
412 | lua_getfield(L,tidx,"address");
413 | (*pa)[i].x25.psdnaddress = luaL_checklstring(L,-1,&(*pa)[i].x25.size);
414 | break;
415 |
416 | case RR_SPF:
417 | lua_getfield(L,tidx,"text");
418 | (*pa)[i].spf.text = luaL_checklstring(L,-1,&(*pa)[i].spf.len);
419 | break;
420 |
421 | case RR_TXT:
422 | lua_getfield(L,tidx,"text");
423 | (*pa)[i].txt.text = luaL_checklstring(L,-1,&(*pa)[i].txt.len);
424 | break;
425 |
426 | case RR_NSAP_PTR:
427 | lua_getfield(L,tidx,"owner");
428 | (*pa)[i].nsap_ptr.owner = luaL_checkstring(L,-1);
429 | break;
430 |
431 | case RR_MD:
432 | lua_getfield(L,tidx,"madname");
433 | (*pa)[i].md.madname = luaL_checkstring(L,-1);
434 | break;
435 |
436 | case RR_MF:
437 | lua_getfield(L,tidx,"madname");
438 | (*pa)[i].mf.madname = luaL_checkstring(L,-1);
439 | break;
440 |
441 | case RR_MB:
442 | lua_getfield(L,tidx,"madname");
443 | (*pa)[i].mb.madname = luaL_checkstring(L,-1);
444 | break;
445 |
446 | case RR_MG:
447 | lua_getfield(L,tidx,"mgmname");
448 | (*pa)[i].mg.mgmname = luaL_checkstring(L,-1);
449 | break;
450 |
451 | case RR_MR:
452 | lua_getfield(L,tidx,"newname");
453 | (*pa)[i].mr.newname = luaL_checkstring(L,-1);
454 | break;
455 |
456 | case RR_NS:
457 | lua_getfield(L,tidx,"nsdname");
458 | (*pa)[i].ns.nsdname = luaL_checkstring(L,-1);
459 | break;
460 |
461 | case RR_PTR:
462 | lua_getfield(L,tidx,"ptr");
463 | (*pa)[i].ptr.ptr = luaL_checkstring(L,-1);
464 | break;
465 |
466 | case RR_CNAME:
467 | lua_getfield(L,tidx,"cname");
468 | (*pa)[i].cname.cname = luaL_checkstring(L,-1);
469 | break;
470 |
471 | case RR_NULL:
472 | lua_getfield(L,tidx,"data");
473 | (*pa)[i].null.data = (uint8_t *)luaL_checklstring(L,-1,&(*pa)[i].null.size);
474 | break;
475 |
476 | case RR_OPT:
477 | lua_getfield(L,tidx,"udp_payload");
478 | lua_getfield(L,tidx,"version");
479 | lua_getfield(L,tidx,"fdo");
480 | lua_getfield(L,tidx,"fug");
481 | lua_getfield(L,tidx,"z");
482 | lua_getfield(L,tidx,"opts");
483 |
484 | (*pa)[i].opt.udp_payload = luaL_checkinteger(L,-6);
485 | (*pa)[i].opt.version = luaL_checkinteger(L,-5);
486 | (*pa)[i].opt.fdo = lua_toboolean(L,-4);
487 | (*pa)[i].opt.fug = luaL_optinteger(L,-3,0);
488 | (*pa)[i].opt.z = luaL_optinteger(L,-2,0);
489 | (*pa)[i].opt.numopts = lua_rawlen(L,-1);
490 | (*pa)[i].opt.opts = lua_newuserdata(L,(*pa)[i].opt.numopts * sizeof(edns0_opt_t));
491 |
492 | for (size_t j = 0 ; j < (*pa)[i].opt.numopts ; j++)
493 | {
494 | lua_pushinteger(L,j + 1);
495 | lua_gettable(L,-3);
496 | lua_getfield(L,-1,"data");
497 | lua_getfield(L,-2,"code");
498 |
499 | (*pa)[i].opt.opts[j].data = (uint8_t *)luaL_checklstring(L,-2,&(*pa)[i].opt.opts[j].len);
500 | if (lua_isnumber(L,-1))
501 | (*pa)[i].opt.opts[j].code = lua_tointeger(L,-1);
502 | else if (lua_isstring(L,-1))
503 | {
504 | if (strcmp("NSID",lua_tostring(L,-1)) == 0)
505 | (*pa)[i].opt.opts[j].code = EDNS0RR_NSID;
506 | else if (strcmp("nsid",lua_tostring(L,-1)) == 0)
507 | (*pa)[i].opt.opts[j].code = EDNS0RR_NSID;
508 | else
509 | luaL_error(L,"OPT RR code '%s' not supported",lua_tostring(L,-1));
510 | }
511 | lua_pop(L,2);
512 | }
513 |
514 | break;
515 |
516 | default: break;
517 | }
518 |
519 | lua_settop(L,top);
520 | }
521 | }
522 |
523 | /********************************************************************/
524 |
525 | static int dnslua_encode(lua_State *L)
526 | {
527 | dns_query_t query;
528 | dns_packet_t buffer[DNS_BUFFER_UDP_MAX];
529 | size_t len;
530 | dns_rcode_t rc;
531 |
532 | luaL_checktype(L,1,LUA_TTABLE);
533 | lua_settop(L,1);
534 |
535 | lua_getfield(L,1,"id");
536 | lua_getfield(L,1,"query");
537 | lua_getfield(L,1,"opcode");
538 | lua_getfield(L,1,"aa");
539 | lua_getfield(L,1,"tc");
540 | lua_getfield(L,1,"rd");
541 | lua_getfield(L,1,"ra");
542 | lua_getfield(L,1,"z");
543 | lua_getfield(L,1,"ad");
544 | lua_getfield(L,1,"cd");
545 | lua_getfield(L,1,"rcode");
546 |
547 | query.id = luaL_checkinteger(L,-11);
548 | query.query = lua_toboolean(L,-10);
549 | query.opcode = dns_op_value(luaL_optstring(L,-9,"QUERY"));
550 | query.aa = lua_toboolean(L,-8);
551 | query.tc = lua_toboolean(L,-7);
552 | query.rd = lua_toboolean(L,-6);
553 | query.ra = lua_toboolean(L,-5);
554 | query.z = lua_toboolean(L,-4);
555 | query.ad = lua_toboolean(L,-3);
556 | query.cd = lua_toboolean(L,-2);
557 | query.rcode = luaL_optinteger(L,-1,RCODE_OKAY);
558 | lua_pop(L,11);
559 |
560 | lua_getfield(L,1,"question");
561 | to_question(L,&query.questions,&query.qdcount,-1);
562 | lua_getfield(L,1,"answers");
563 | to_answers(L,&query.answers,&query.ancount,-1);
564 | lua_getfield(L,1,"nameservers");
565 | to_answers(L,&query.nameservers,&query.nscount,-1);
566 | lua_getfield(L,1,"additional");
567 | to_answers(L,&query.additional,&query.arcount,-1);
568 |
569 | len = sizeof(buffer);
570 | rc = dns_encode(buffer,&len,&query);
571 |
572 | if (rc != RCODE_OKAY)
573 | {
574 | lua_pushnil(L);
575 | lua_pushinteger(L,rc);
576 | return 2;
577 | }
578 |
579 | lua_pushlstring(L,(char *)buffer,len);
580 | lua_pushinteger(L,0);
581 | return 2;
582 | }
583 |
584 | /********************************************************************/
585 |
586 | static void push_dnsgpos_angle(lua_State *L,dnsgpos_angle *pa,bool lat)
587 | {
588 | lua_createtable(L,0,4);
589 | lua_pushinteger(L,pa->deg);
590 | lua_setfield(L,-2,"deg");
591 | lua_pushinteger(L,pa->min);
592 | lua_setfield(L,-2,"min");
593 | lua_pushnumber(L,(double)pa->sec + ((double)pa->frac / 1000.0));
594 | lua_setfield(L,-2,"sec");
595 | lua_pushboolean(L,pa->nw);
596 | lua_setfield(L,-2,"nw");
597 | if (lat)
598 | lua_pushlstring(L,(pa->nw) ? "N" : "S" , 1);
599 | else
600 | lua_pushlstring(L,(pa->nw) ? "W" : "E" , 1);
601 | lua_setfield(L,-2,"hemisphere");
602 | }
603 |
604 | /********************************************************************/
605 |
606 | static void decode_answer(
607 | lua_State *L,
608 | int tab,
609 | const char *name,
610 | dns_answer_t *pans,
611 | size_t cnt
612 | )
613 | {
614 | char ipaddr[INET6_ADDRSTRLEN];
615 |
616 | lua_createtable(L,cnt,0);
617 |
618 | for (size_t i = 0 ; i < cnt ; i++)
619 | {
620 | lua_pushinteger(L,i + 1);
621 | lua_createtable(L,0,0);
622 |
623 | lua_pushstring(L,pans[i].generic.name);
624 | lua_setfield(L,-2,"name");
625 | lua_pushinteger(L,pans[i].generic.ttl);
626 | lua_setfield(L,-2,"ttl");
627 | lua_pushstring(L,dns_class_text(pans[i].generic.class));
628 | lua_setfield(L,-2,"class");
629 | lua_pushstring(L,dns_type_text(pans[i].generic.type));
630 | lua_setfield(L,-2,"type");
631 |
632 | switch(pans[i].generic.type)
633 | {
634 | case RR_A:
635 | inet_ntop(AF_INET,&pans[i].a.address,ipaddr,sizeof(ipaddr));
636 | lua_pushstring(L,ipaddr);
637 | lua_setfield(L,-2,"address");
638 | lua_pushlstring(L,(char *)&pans[i].a.address,4);
639 | lua_setfield(L,-2,"raw_address");
640 | break;
641 |
642 | case RR_SOA:
643 | lua_pushstring(L,pans[i].soa.mname);
644 | lua_setfield(L,-2,"mname");
645 | lua_pushstring(L,pans[i].soa.rname);
646 | lua_setfield(L,-2,"rname");
647 | lua_pushnumber(L,pans[i].soa.serial);
648 | lua_setfield(L,-2,"serial");
649 | lua_pushnumber(L,pans[i].soa.refresh);
650 | lua_setfield(L,-2,"refresh");
651 | lua_pushnumber(L,pans[i].soa.retry);
652 | lua_setfield(L,-2,"retry");
653 | lua_pushnumber(L,pans[i].soa.expire);
654 | lua_setfield(L,-2,"expire");
655 | lua_pushnumber(L,pans[i].soa.minimum);
656 | lua_setfield(L,-2,"minimum");
657 | break;
658 |
659 | case RR_NAPTR:
660 | lua_pushinteger(L,pans[i].naptr.order);
661 | lua_setfield(L,-2,"order");
662 | lua_pushinteger(L,pans[i].naptr.preference);
663 | lua_setfield(L,-2,"preference");
664 | lua_pushstring(L,pans[i].naptr.flags);
665 | lua_setfield(L,-2,"flags");
666 | lua_pushstring(L,pans[i].naptr.services);
667 | lua_setfield(L,-2,"services");
668 | lua_pushstring(L,pans[i].naptr.regexp);
669 | lua_setfield(L,-2,"regexp");
670 | lua_pushstring(L,pans[i].naptr.replacement);
671 | lua_setfield(L,-2,"replacement");
672 | break;
673 |
674 | case RR_AAAA:
675 | inet_ntop(AF_INET6,&pans[i].aaaa.address,ipaddr,sizeof(ipaddr));
676 | lua_pushstring(L,ipaddr);
677 | lua_setfield(L,-2,"address");
678 | lua_pushlstring(L,(char *)&pans[i].aaaa.address,16);
679 | lua_setfield(L,-2,"raw_address");
680 | break;
681 |
682 | case RR_SRV:
683 | lua_pushinteger(L,pans[i].srv.priority);
684 | lua_setfield(L,-2,"priority");
685 | lua_pushinteger(L,pans[i].srv.weight);
686 | lua_setfield(L,-2,"weight");
687 | lua_pushinteger(L,pans[i].srv.port);
688 | lua_setfield(L,-2,"port");
689 | lua_pushstring(L,pans[i].srv.target);
690 | lua_setfield(L,-2,"target");
691 | break;
692 |
693 | case RR_WKS:
694 | inet_ntop(AF_INET,&pans[i].wks.address,ipaddr,sizeof(ipaddr));
695 | lua_pushstring(L,ipaddr);
696 | lua_setfield(L,-2,"address");
697 | lua_pushlstring(L,(char *)&pans[i].wks.address,4);
698 | lua_setfield(L,-2,"raw_address");
699 | lua_pushinteger(L,pans[i].wks.protocol);
700 | lua_setfield(L,-2,"protocol");
701 | lua_pushlstring(L,(char *)pans[i].wks.bits,pans[i].wks.numbits);
702 | lua_setfield(L,-2,"bits");
703 | break;
704 |
705 | case RR_GPOS:
706 | push_dnsgpos_angle(L,&pans[i].gpos.latitude,true);
707 | lua_setfield(L,-2,"longitude");
708 | push_dnsgpos_angle(L,&pans[i].gpos.longitude,false);
709 | lua_setfield(L,-2,"latitude");
710 | lua_pushnumber(L,pans[i].gpos.altitude);
711 | lua_setfield(L,-2,"altitude");
712 | break;
713 |
714 | case RR_LOC:
715 | lua_pushnumber(L,pans[i].loc.size);
716 | lua_setfield(L,-2,"size");
717 | lua_pushnumber(L,pans[i].loc.horiz_pre);
718 | lua_setfield(L,-2,"horiz_pre");
719 | lua_pushnumber(L,pans[i].loc.vert_pre);
720 | lua_setfield(L,-2,"vert_pre");
721 | push_dnsgpos_angle(L,&pans[i].loc.latitude,true);
722 | lua_setfield(L,-2,"latitude");
723 | push_dnsgpos_angle(L,&pans[i].loc.longitude,false);
724 | lua_setfield(L,-2,"longitude");
725 | lua_pushnumber(L,pans[i].loc.altitude);
726 | lua_setfield(L,-2,"altitude");
727 | break;
728 |
729 | case RR_PX:
730 | lua_pushstring(L,pans[i].px.map822);
731 | lua_setfield(L,-2,"map822");
732 | lua_pushstring(L,pans[i].px.mapx400);
733 | lua_setfield(L,-2,"mapx400");
734 | break;
735 |
736 | case RR_RP:
737 | lua_pushstring(L,pans[i].rp.mbox);
738 | lua_setfield(L,-2,"mbox");
739 | lua_pushstring(L,pans[i].rp.domain);
740 | lua_setfield(L,-2,"domain");
741 | break;
742 |
743 | case RR_MINFO:
744 | lua_pushstring(L,pans[i].minfo.rmailbx);
745 | lua_setfield(L,-2,"rmailbx");
746 | lua_pushstring(L,pans[i].minfo.emailbx);
747 | lua_setfield(L,-2,"emailbx");
748 | break;
749 |
750 | case RR_AFSDB:
751 | lua_pushinteger(L,pans[i].afsdb.subtype);
752 | lua_setfield(L,-2,"subtype");
753 | lua_pushstring(L,pans[i].afsdb.hostname);
754 | lua_setfield(L,-2,"hostname");
755 | break;
756 |
757 | case RR_RT:
758 | lua_pushinteger(L,pans[i].rt.preference);
759 | lua_setfield(L,-2,"preference");
760 | lua_pushstring(L,pans[i].rt.host);
761 | lua_setfield(L,-2,"host");
762 | break;
763 |
764 | case RR_MX:
765 | lua_pushinteger(L,pans[i].mx.preference);
766 | lua_setfield(L,-2,"preference");
767 | lua_pushstring(L,pans[i].mx.exchange);
768 | lua_setfield(L,-2,"exchange");
769 | break;
770 |
771 | case RR_NSAP:
772 | lua_pushstring(L,pans[i].nsap.length);
773 | lua_setfield(L,-2,"length");
774 | lua_pushstring(L,pans[i].nsap.nsapaddress);
775 | lua_setfield(L,-2,"address");
776 | break;
777 |
778 | case RR_ISDN:
779 | lua_pushstring(L,pans[i].isdn.isdnaddress);
780 | lua_setfield(L,-2,"address");
781 | lua_pushstring(L,pans[i].isdn.sa);
782 | lua_setfield(L,-2,"sa");
783 | break;
784 |
785 | case RR_HINFO:
786 | lua_pushstring(L,pans[i].hinfo.cpu);
787 | lua_setfield(L,-2,"cpu");
788 | lua_pushstring(L,pans[i].hinfo.os);
789 | lua_setfield(L,-2,"os");
790 | break;
791 |
792 | case RR_X25:
793 | lua_pushlstring(L,pans[i].x25.psdnaddress,pans[i].x25.size);
794 | lua_setfield(L,-2,"address");
795 | break;
796 |
797 | case RR_SPF:
798 | lua_pushlstring(L,pans[i].spf.text,pans[i].spf.len);
799 | lua_setfield(L,-2,"text");
800 | break;
801 |
802 | case RR_TXT:
803 | lua_pushlstring(L,pans[i].txt.text,pans[i].txt.len);
804 | lua_setfield(L,-2,"text");
805 | break;
806 |
807 | case RR_NSAP_PTR:
808 | lua_pushstring(L,pans[i].nsap_ptr.owner);
809 | lua_setfield(L,-2,"owner");
810 | break;
811 |
812 | case RR_MD:
813 | lua_pushstring(L,pans[i].md.madname);
814 | lua_setfield(L,-2,"madname");
815 | break;
816 |
817 | case RR_MF:
818 | lua_pushstring(L,pans[i].mf.madname);
819 | lua_setfield(L,-2,"madname");
820 | break;
821 |
822 | case RR_MB:
823 | lua_pushstring(L,pans[i].mb.madname);
824 | lua_setfield(L,-2,"madname");
825 | break;
826 |
827 | case RR_MG:
828 | lua_pushstring(L,pans[i].mg.mgmname);
829 | lua_setfield(L,-2,"mgmname");
830 | break;
831 |
832 | case RR_MR:
833 | lua_pushstring(L,pans[i].mr.newname);
834 | lua_setfield(L,-2,"newname");
835 | break;
836 |
837 | case RR_NS:
838 | lua_pushstring(L,pans[i].ns.nsdname);
839 | lua_setfield(L,-2,"nsdname");
840 | break;
841 |
842 | case RR_PTR:
843 | lua_pushstring(L,pans[i].ptr.ptr);
844 | lua_setfield(L,-2,"ptr");
845 | break;
846 |
847 | case RR_CNAME:
848 | lua_pushstring(L,pans[i].cname.cname);
849 | lua_setfield(L,-2,"cname");
850 | break;
851 |
852 | case RR_NULL:
853 | lua_pushlstring(L,(char *)pans[i].null.data,pans[i].null.size);
854 | lua_setfield(L,-2,"data");
855 | break;
856 |
857 | case RR_OPT:
858 | lua_pushinteger(L,pans[i].opt.udp_payload);
859 | lua_setfield(L,-2,"udp_payload");
860 | lua_pushinteger(L,pans[i].opt.version);
861 | lua_setfield(L,-2,"version");
862 | lua_pushboolean(L,pans[i].opt.fdo);
863 | lua_setfield(L,-2,"fdo");
864 | lua_pushinteger(L,pans[i].opt.fug);
865 | lua_setfield(L,-2,"fug");
866 | lua_pushinteger(L,pans[i].opt.z);
867 | lua_setfield(L,-2,"z");
868 | lua_createtable(L,pans[i].opt.numopts,0);
869 | for (size_t j = 0 ; j < pans[i].opt.numopts ; j++)
870 | {
871 | lua_pushinteger(L,j + 1);
872 | lua_createtable(L,0,2);
873 | lua_pushlstring(L,(char *)pans[i].opt.opts[j].data,pans[i].opt.opts[j].len);
874 | lua_setfield(L,-2,"data");
875 | if (pans[i].opt.opts[j].code == EDNS0RR_NSID)
876 | lua_pushstring(L,"NSID");
877 | else
878 | lua_pushinteger(L,pans[i].opt.opts[j].code);
879 | lua_setfield(L,-2,"code");
880 | lua_settable(L,-3);
881 | }
882 | lua_setfield(L,-2,"opts");
883 | break;
884 |
885 | default:
886 | lua_pushlstring(L,(char *)pans[i].x.rawdata,pans[i].x.size);
887 | lua_setfield(L,-2,"rawdata");
888 | break;
889 | }
890 |
891 | lua_settable(L,-3);
892 | }
893 |
894 | lua_setfield(L,tab,name);
895 | }
896 |
897 | /**********************************************************************/
898 |
899 | static int dnslua_decode(lua_State *L)
900 | {
901 | dns_decoded_t bufresult[DNS_DECODEBUF_8K];
902 | dns_packet_t data [DNS_DECODEBUF_4K];
903 | const char *luadata;
904 | dns_query_t *result;
905 | size_t size;
906 | int tab;
907 | int rc;
908 |
909 | /*---------------------------------------------------------------------
910 | ; We need to make sure our data is properly aligned. And hey, this is
911 | ; Lua---a scripting lanague. We can afford a bit of waste 8-)
912 | ;----------------------------------------------------------------------*/
913 |
914 | luadata = luaL_checklstring(L,1,&size);
915 | if (size > sizeof(data)) size = sizeof(data);
916 | memcpy(data,luadata,size);
917 |
918 | rc = dns_decode(bufresult,&(size_t){sizeof(bufresult)},data,size);
919 |
920 | if (rc != RCODE_OKAY)
921 | {
922 | lua_pushnil(L);
923 | lua_pushinteger(L,rc);
924 | return 2;
925 | }
926 |
927 | result = (dns_query_t *)bufresult;
928 |
929 | lua_createtable(L,0,0);
930 | tab = lua_gettop(L);
931 |
932 | lua_pushinteger(L,result->id);
933 | lua_setfield(L,tab,"id");
934 | lua_pushboolean(L,result->query);
935 | lua_setfield(L,tab,"query");
936 | lua_pushstring(L,dns_op_text(result->opcode));
937 | lua_setfield(L,tab,"opcode");
938 | lua_pushboolean(L,result->aa);
939 | lua_setfield(L,tab,"aa");
940 | lua_pushboolean(L,result->tc);
941 | lua_setfield(L,tab,"tc");
942 | lua_pushboolean(L,result->rd);
943 | lua_setfield(L,tab,"rd");
944 | lua_pushboolean(L,result->ra);
945 | lua_setfield(L,tab,"ra");
946 | lua_pushboolean(L,result->z);
947 | lua_setfield(L,tab,"z");
948 | lua_pushboolean(L,result->ad);
949 | lua_setfield(L,tab,"ad");
950 | lua_pushboolean(L,result->cd);
951 | lua_setfield(L,tab,"cd");
952 | lua_pushinteger(L,result->rcode);
953 | lua_setfield(L,tab,"rcode");
954 |
955 | if (result->qdcount)
956 | {
957 | lua_createtable(L,0,3);
958 | lua_pushstring(L,result->questions[0].name);
959 | lua_setfield(L,-2,"name");
960 | lua_pushstring(L,dns_class_text(result->questions[0].class));
961 | lua_setfield(L,-2,"class");
962 | lua_pushstring(L,dns_type_text(result->questions[0].type));
963 | lua_setfield(L,-2,"type");
964 | lua_setfield(L,tab,"question");
965 | }
966 |
967 | decode_answer(L,tab,"answers" , result->answers , result->ancount);
968 | decode_answer(L,tab,"nameservers" , result->nameservers, result->nscount);
969 | decode_answer(L,tab,"additional" , result->additional , result->arcount);
970 |
971 | assert(tab == lua_gettop(L));
972 | lua_pushinteger(L,0);
973 | return 2;
974 | }
975 |
976 | /*********************************************************************/
977 |
978 | static int dnslua_strerror(lua_State *L)
979 | {
980 | if (lua_isnumber(L,1))
981 | lua_pushstring(L,dns_rcode_text(lua_tointeger(L,1)));
982 | else
983 | lua_pushliteral(L,"uninown error");
984 | return 1;
985 | }
986 |
987 | /*********************************************************************/
988 |
989 | static int dnslua_query(lua_State *L)
990 | {
991 | sockaddr_all srvaddr;
992 | const char *server;
993 | const char *luaquery;
994 | size_t querysize;
995 | dns_packet_t query[DNS_BUFFER_UDP_MAX];
996 | dns_packet_t reply[DNS_DECODEBUF_4K];
997 | size_t replysize;
998 | int rc;
999 |
1000 | server = luaL_checkstring(L,1);
1001 | luaquery = luaL_checklstring(L,2,&querysize);
1002 |
1003 | if (net_server(&srvaddr,server) < 0)
1004 | luaL_error(L,"%s is not an IPv4/IPv6 address",server);
1005 |
1006 | if (querysize > MAX_DNS_QUERY_SIZE) querysize = MAX_DNS_QUERY_SIZE;
1007 | memcpy(query,luaquery,querysize);
1008 | replysize = sizeof(reply);
1009 | rc = net_request(&srvaddr,reply,&replysize,query,querysize);
1010 |
1011 | if (rc != 0)
1012 | {
1013 | lua_pushnil(L);
1014 | lua_pushinteger(L,rc);
1015 | return 2;
1016 | }
1017 |
1018 | lua_pushlstring(L,(char *)reply,replysize);
1019 | lua_pushinteger(L,0);
1020 | return 2;
1021 | }
1022 |
1023 | /**********************************************************************/
1024 |
1025 | static const struct luaL_Reg reg_dns[] =
1026 | {
1027 | { "encode" , dnslua_encode } ,
1028 | { "decode" , dnslua_decode } ,
1029 | { "strerror" , dnslua_strerror } ,
1030 | { "query" , dnslua_query } ,
1031 | { NULL , NULL }
1032 | };
1033 |
1034 | int luaopen_org_conman_dns(lua_State *L)
1035 | {
1036 | #if LUA_VERSION_NUM == 501
1037 | luaL_register(L,"org.conman.dns",reg_dns);
1038 | #else
1039 | luaL_newlib(L,reg_dns);
1040 | #endif
1041 |
1042 | lua_createtable(L,0,0);
1043 | for (size_t i = 0 ; c_dns_rcode_enum[i].text != NULL ; i++)
1044 | {
1045 | lua_pushinteger(L,c_dns_rcode_enum[i].value);
1046 | lua_setfield(L,-2,c_dns_rcode_enum[i].text);
1047 | }
1048 | lua_setfield(L,-2,"errno");
1049 |
1050 | lua_pushliteral(L,VERSION);
1051 | lua_setfield(L,-2,"_VERSION");
1052 |
1053 | return 1;
1054 | }
1055 |
1056 | /**********************************************************************/
1057 |
--------------------------------------------------------------------------------
/src/mappings.c:
--------------------------------------------------------------------------------
1 | /*************************************************************************
2 | *
3 | * Copyright 2010 by Sean Conner. All Rights Reserved.
4 | *
5 | * This library is free software; you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published by
7 | * the Free Software Foundation; either version 3 of the License, or (at your
8 | * option) any later version.
9 | *
10 | * This library is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
13 | * License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this library; if not, see .
17 | *
18 | **************************************************************************/
19 |
20 | /***********************************************************************
21 | *
22 | * Implementation of mapping values to strings, or strings to values.
23 | *
24 | * This code is written to C99.
25 | *
26 | ************************************************************************/
27 |
28 | #include
29 | #include
30 | #include
31 | #include
32 |
33 | #include "dns.h"
34 | #include "mappings.h"
35 |
36 | /*******************************************************************
37 | *
38 | * The following structure is used to map strings to values. The arrays
39 | * defined by this structure *MUST* be sorted by the strings in ascending
40 | * order.
41 | *
42 | *********************************************************************/
43 |
44 | struct string_int_map
45 | {
46 | char const *const text;
47 | int const value;
48 | };
49 |
50 | /************************************************************************/
51 |
52 | static struct int_string_map const cm_dns_rcode[] =
53 | {
54 | { RCODE_OKAY , "No error" } ,
55 | { RCODE_FORMAT_ERROR , "Format error" } ,
56 | { RCODE_SERVER_FAILURE , "Server failure" } ,
57 | { RCODE_NAME_ERROR , "Non-existant domain" } ,
58 | { RCODE_NOT_IMPLEMENTED , "Not implemented" } ,
59 | { RCODE_REFUSED , "Query refused" } ,
60 | { RCODE_YXDOMAIN , "Name exists when it should not" } ,
61 | { RCODE_YXRRSET , "RRset exists when it should not" } ,
62 | { RCODE_NXRRSET , "RRset does not exist" } ,
63 | { RCODE_NOTAUTH , "Server not authoritative" } ,
64 | { RCODE_NOTZONE , "Zone not in zone section" } ,
65 | { RCODE_BADVERS , "Bad OPT version/TSIG failed" } ,
66 | { RCODE_BADKEY , "Key not recognized" } ,
67 | { RCODE_BADTIME , "Signature out of time window" } ,
68 | { RCODE_BADMODE , "Bad TKEY mode" } ,
69 | { RCODE_BADNAME , "Duplicate key name" } ,
70 | { RCODE_BADALG , "Algorithm not supported" } ,
71 | { RCODE_BADTRUC , "Bad truncation" } ,
72 | { RCODE_BADCOOKIE , "Bad/missing server cookie" } ,
73 | { RCODE_NO_MEMORY , "No memory" } ,
74 | { RCODE_BAD_STRING , "Bad sring" } ,
75 | };
76 |
77 | #define RCODE_COUNT (sizeof(cm_dns_rcode) / sizeof(struct int_string_map))
78 |
79 | struct int_string_map const c_dns_rcode_enum[] =
80 | {
81 | { RCODE_OKAY , "OKAY" } ,
82 | { RCODE_FORMAT_ERROR , "FORMAT_ERROR" } ,
83 | { RCODE_SERVER_FAILURE , "SERVER_FAILURE" } ,
84 | { RCODE_NAME_ERROR , "NAME_ERROR" } ,
85 | { RCODE_NOT_IMPLEMENTED , "NOT_IMPLEMENTED" } ,
86 | { RCODE_REFUSED , "REFUSED" } ,
87 | { RCODE_YXDOMAIN , "YXDOMAIN" } ,
88 | { RCODE_YXRRSET , "YXRRSET" } ,
89 | { RCODE_NXRRSET , "NXRRSET" } ,
90 | { RCODE_NOTAUTH , "NOTAUTH" } ,
91 | { RCODE_NOTZONE , "NOTZONE" } ,
92 | { RCODE_BADVERS , "BADVERS" } ,
93 | { RCODE_BADKEY , "BADKEY" } ,
94 | { RCODE_BADTIME , "BADTIME" } ,
95 | { RCODE_BADMODE , "BADMODE" } ,
96 | { RCODE_BADNAME , "BADNAME" } ,
97 | { RCODE_BADALG , "BADALG" } ,
98 | { RCODE_BADTRUC , "BADTRUNC" } ,
99 | { RCODE_BADCOOKIE , "BADCOOKIE" } ,
100 | { RCODE_NO_MEMORY , "NO_MEMORY" } ,
101 | { RCODE_BAD_STRING , "BAD_STRING" } ,
102 | { 0 , NULL } ,
103 | };
104 |
105 | static struct string_int_map const cm_dns_rcode_is[] =
106 | {
107 | { "BADALG" , RCODE_BADALG } ,
108 | { "BADCOOKIE" , RCODE_BADCOOKIE } ,
109 | { "BADKEY" , RCODE_BADKEY } ,
110 | { "BADMODE" , RCODE_BADMODE } ,
111 | { "BADNAME" , RCODE_BADNAME } ,
112 | { "BADTIME" , RCODE_BADTIME } ,
113 | { "BADTRUNC" , RCODE_BADTRUC } ,
114 | { "BADVERS" , RCODE_BADVERS } ,
115 | { "BAD_STRING" , RCODE_BAD_STRING } ,
116 | { "FORMAT_ERROR" , RCODE_FORMAT_ERROR } ,
117 | { "NAME_ERROR" , RCODE_NAME_ERROR } ,
118 | { "NOTAUTH" , RCODE_NOTAUTH } ,
119 | { "NOTZONE" , RCODE_NOTZONE } ,
120 | { "NOT_IMPLEMENTED" , RCODE_NOT_IMPLEMENTED } ,
121 | { "NO_MEMORY" , RCODE_NO_MEMORY } ,
122 | { "NXRRSET" , RCODE_NXRRSET } ,
123 | { "OKAY" , RCODE_OKAY } ,
124 | { "REFUSED" , RCODE_REFUSED } ,
125 | { "SERVER_FAILURE" , RCODE_SERVER_FAILURE } ,
126 | { "YXDOMAIN" , RCODE_YXDOMAIN } ,
127 | { "YXRRSET" , RCODE_YXRRSET } ,
128 | };
129 |
130 | static struct int_string_map const cm_dns_type[] =
131 | {
132 | { RR_A , "A" } ,
133 | { RR_NS , "NS" } ,
134 | { RR_MD , "MD" } ,
135 | { RR_MF , "MF" } ,
136 | { RR_CNAME , "CNAME" } ,
137 | { RR_SOA , "SOA" } ,
138 | { RR_MB , "MB" } ,
139 | { RR_MG , "MG" } ,
140 | { RR_MR , "MR" } ,
141 | { RR_NULL , "NULL" } ,
142 | { RR_WKS , "WKS" } ,
143 | { RR_PTR , "PTR" } ,
144 | { RR_HINFO , "HINFO" } ,
145 | { RR_MINFO , "MINFO" } ,
146 | { RR_MX , "MX" } ,
147 | { RR_TXT , "TXT" } ,
148 | { RR_RP , "RP" } ,
149 | { RR_AFSDB , "AFSDB" } ,
150 | { RR_X25 , "X25" } ,
151 | { RR_ISDN , "ISDN" } ,
152 | { RR_RT , "RT" } ,
153 | { RR_NSAP , "NSAP" } ,
154 | { RR_NSAP_PTR , "NSAP-PTR" } ,
155 | { RR_SIG , "SIG" } ,
156 | { RR_KEY , "KEY" } ,
157 | { RR_PX , "PX" } ,
158 | { RR_GPOS , "GPOS" } ,
159 | { RR_AAAA , "AAAA" } ,
160 | { RR_LOC , "LOC" } ,
161 | { RR_NXT , "NXT" } ,
162 | { RR_EID , "EID" } ,
163 | { RR_NIMLOC , "NIMLOC" } ,
164 | { RR_SRV , "SRV" } ,
165 | { RR_ATMA , "ATMA" } ,
166 | { RR_NAPTR , "NAPTR" } ,
167 | { RR_KX , "KX" } ,
168 | { RR_CERT , "CERT" } ,
169 | { RR_A6 , "A6" } ,
170 | { RR_DNAME , "DNAME" } ,
171 | { RR_SINK , "SINK" } ,
172 | { RR_OPT , "OPT" } ,
173 | { RR_APL , "APL" } ,
174 | { RR_DS , "DS" } ,
175 | { RR_SSHFP , "SSHFP" } ,
176 | { RR_ISECKEY , "ISECKEY" } ,
177 | { RR_RRSIG , "RRSIG" } ,
178 | { RR_NSEC , "NSEC" } ,
179 | { RR_DNSKEY , "DNSKEY" } ,
180 | { RR_DHCID , "DHCID" } ,
181 | { RR_NSEC3 , "NSEC3" } ,
182 | { RR_NSEC3PARAM , "NSEC3PARAM" } ,
183 | { RR_TLSA , "TLSA" } ,
184 | { RR_SMIMEA , "SMIMEA" } ,
185 | { RR_HIP , "HIP" } ,
186 | { RR_NINFO , "NINFO" } ,
187 | { RR_RKEY , "RKEY" } ,
188 | { RR_TALINK , "TALINK" } ,
189 | { RR_CDS , "CDS" } ,
190 | { RR_CDNSKEY , "CDNSKEY" } ,
191 | { RR_OPENPGPKEY , "OPENPGPKEY" } ,
192 | { RR_CSYNC , "CSYNC" } ,
193 | { RR_ZONEMD , "ZONEMD" } ,
194 | { RR_HTTPS , "HTTPS" } ,
195 | { RR_SPF , "SPF" } ,
196 | { RR_UINFO , "UINFO" } ,
197 | { RR_UID , "UID" } ,
198 | { RR_GID , "GID" } ,
199 | { RR_UNSPEC , "UNSPEC" } ,
200 | { RR_NID , "NID" } ,
201 | { RR_L32 , "L32" } ,
202 | { RR_L64 , "L64" } ,
203 | { RR_LP , "LP" } ,
204 | { RR_EUI48 , "EUI48" } ,
205 | { RR_EUI64 , "EUI64" } ,
206 | { RR_TKEY , "TKEY" } ,
207 | { RR_TSIG , "TSIG" } ,
208 | { RR_IXFR , "IXFR" } ,
209 | { RR_AXFR , "AXFR" } ,
210 | { RR_MAILB , "MAILB" } ,
211 | { RR_MAILA , "MAILA" } ,
212 | { RR_ANY , "ANY" } ,
213 | { RR_URI , "URI" } ,
214 | { RR_CAA , "CAA" } ,
215 | { RR_AVC , "AVC" } ,
216 | { RR_DOA , "DOA" } ,
217 | { RR_AMTRELAY , "AMTRELAY" } ,
218 | { RR_TA , "TA" } ,
219 | { RR_DLV , "DLV" } ,
220 | { RR_PRIVATE , "PRIVATE" } ,
221 | { RR_UNKNOWN , "UNKNOWN" } ,
222 | };
223 |
224 | #define TYPE_COUNT (sizeof(cm_dns_type) / sizeof(struct int_string_map))
225 |
226 | static struct string_int_map const cm_dns_type_is[] =
227 | {
228 | { "A" , RR_A } ,
229 | { "A6" , RR_A6 } ,
230 | { "AAAA" , RR_AAAA } ,
231 | { "AFSDB" , RR_AFSDB } ,
232 | { "AMTRELAY" , RR_AMTRELAY } ,
233 | { "ANY" , RR_ANY } ,
234 | { "APL" , RR_APL } ,
235 | { "ATMA" , RR_ATMA } ,
236 | { "AVC" , RR_AVC } ,
237 | { "AXFR" , RR_AXFR } ,
238 | { "CAA" , RR_CAA } ,
239 | { "CDNSKEY" , RR_CDNSKEY } ,
240 | { "CDS" , RR_CDS } ,
241 | { "CERT" , RR_CERT } ,
242 | { "CNAME" , RR_CNAME } ,
243 | { "CSYNC" , RR_CSYNC } ,
244 | { "DHCID" , RR_DHCID } ,
245 | { "DLV" , RR_DLV } ,
246 | { "DNAME" , RR_DNAME } ,
247 | { "DNSKEY" , RR_DNSKEY } ,
248 | { "DOA" , RR_DOA } ,
249 | { "DS" , RR_DS } ,
250 | { "EID" , RR_EID } ,
251 | { "EUI48" , RR_EUI48 } ,
252 | { "EUI64" , RR_EUI64 } ,
253 | { "GID" , RR_GID } ,
254 | { "GPOS" , RR_GPOS } ,
255 | { "HINFO" , RR_HINFO } ,
256 | { "HIP" , RR_HIP } ,
257 | { "HTTPS" , RR_HTTPS } ,
258 | { "ISDN" , RR_ISDN } ,
259 | { "ISECKEY" , RR_ISECKEY } ,
260 | { "IXFR" , RR_IXFR } ,
261 | { "KEY" , RR_KEY } ,
262 | { "KX" , RR_KX } ,
263 | { "L32" , RR_L32 } ,
264 | { "L64" , RR_L64 } ,
265 | { "LOC" , RR_LOC } ,
266 | { "LP" , RR_LP } ,
267 | { "MAILA" , RR_MAILA } ,
268 | { "MAILB" , RR_MAILB } ,
269 | { "MB" , RR_MB } ,
270 | { "MD" , RR_MD } ,
271 | { "MF" , RR_MF } ,
272 | { "MG" , RR_MG } ,
273 | { "MINFO" , RR_MINFO } ,
274 | { "MR" , RR_MR } ,
275 | { "MX" , RR_MX } ,
276 | { "NAPTR" , RR_NAPTR } ,
277 | { "NID" , RR_NID } ,
278 | { "NIMLOC" , RR_NIMLOC } ,
279 | { "NINFO" , RR_NINFO } ,
280 | { "NS" , RR_NS } ,
281 | { "NSAP" , RR_NSAP } ,
282 | { "NSAP-PTR" , RR_NSAP_PTR } ,
283 | { "NSEC" , RR_NSEC } ,
284 | { "NSEC3" , RR_NSEC3 } ,
285 | { "NSEC3PARAM" , RR_NSEC3PARAM } ,
286 | { "NULL" , RR_NULL } ,
287 | { "NXT" , RR_NXT } ,
288 | { "OPENPGPKEY" , RR_OPENPGPKEY } ,
289 | { "OPT" , RR_OPT } ,
290 | { "PRIVATE" , RR_PRIVATE } ,
291 | { "PTR" , RR_PTR } ,
292 | { "PX" , RR_PX } ,
293 | { "RKEY" , RR_RKEY } ,
294 | { "RP" , RR_RP } ,
295 | { "RRSIG" , RR_RRSIG } ,
296 | { "RT" , RR_RT } ,
297 | { "SIG" , RR_SIG } ,
298 | { "SINK" , RR_SINK } ,
299 | { "SMIMEA" , RR_SMIMEA } ,
300 | { "SOA" , RR_SOA } ,
301 | { "SPF" , RR_SPF } ,
302 | { "SRV" , RR_SRV } ,
303 | { "SSHFP" , RR_SSHFP } ,
304 | { "TA" , RR_TA } ,
305 | { "TALINK" , RR_TALINK } ,
306 | { "TKEY" , RR_TKEY } ,
307 | { "TLSA" , RR_TLSA } ,
308 | { "TSIG" , RR_TSIG } ,
309 | { "TXT" , RR_TXT } ,
310 | { "UID" , RR_UID } ,
311 | { "UINFO" , RR_UINFO } ,
312 | { "UNKNOWN" , RR_UNKNOWN } ,
313 | { "UNSPEC" , RR_UNSPEC } ,
314 | { "URI" , RR_URI } ,
315 | { "WKS" , RR_WKS } ,
316 | { "X25" , RR_X25 } ,
317 | { "ZONEMD" , RR_ZONEMD } ,
318 | };
319 |
320 | static struct int_string_map const cm_dns_class[] =
321 | {
322 | { CLASS_IN , "IN" } ,
323 | { CLASS_CS , "CS" } ,
324 | { CLASS_CH , "CH" } ,
325 | { CLASS_HS , "HS" } ,
326 | { CLASS_NONE , "NONE" } ,
327 | { CLASS_ANY , "ANY" } ,
328 | { CLASS_PRIVATE , "PRIVATE" } ,
329 | { CLASS_UNKNOWN , "UNKNOWN" } ,
330 | };
331 |
332 | #define CLASS_COUNT (sizeof(cm_dns_class) / sizeof(struct int_string_map))
333 |
334 | static struct string_int_map const cm_dns_class_is[] =
335 | {
336 | { "ANY" , CLASS_ANY } ,
337 | { "CH" , CLASS_CH } ,
338 | { "CS" , CLASS_CS } ,
339 | { "HS" , CLASS_HS } ,
340 | { "IN" , CLASS_IN } ,
341 | { "NONE" , CLASS_NONE } ,
342 | { "PRIVATE" , CLASS_PRIVATE } ,
343 | { "UNKNOWN" , CLASS_UNKNOWN } ,
344 | };
345 |
346 | static struct int_string_map const cm_dns_op[] =
347 | {
348 | { OP_QUERY , "QUERY" } ,
349 | { OP_UNKNOWN , "UKNOWN" } ,
350 | { OP_STATUS , "STATUS" } ,
351 | { OP_NOTIFY , "NOTIFY" } ,
352 | { OP_UPDATE , "UPDATE" } ,
353 | };
354 |
355 | #define OP_COUNT (sizeof(cm_dns_op) / sizeof(struct int_string_map))
356 |
357 | static struct string_int_map const cm_dns_op_is[] =
358 | {
359 | { "NOTIFY" , OP_NOTIFY } ,
360 | { "QUERY" , OP_QUERY } ,
361 | { "STATUS" , OP_STATUS } ,
362 | { "UNKNOWN" , OP_UNKNOWN } ,
363 | { "UPDATE" , OP_UPDATE } ,
364 | };
365 |
366 | /*************************************************************************/
367 |
368 | static int intstr_cmp(void const *needle,void const *haystack)
369 | {
370 | struct int_string_map const *pism = haystack;
371 | int const *pi = needle;
372 |
373 | assert(needle != NULL);
374 | assert(haystack != NULL);
375 |
376 | return *pi - pism->value;
377 | }
378 |
379 | /*********************************************************************/
380 |
381 | static int strint_cmp(void const *needle,void const *haystack)
382 | {
383 | struct string_int_map const *psim = haystack;
384 | char const *key = needle;
385 |
386 | assert(needle != NULL);
387 | assert(haystack != NULL);
388 |
389 | return strcmp(key,psim->text);
390 | }
391 |
392 | /**********************************************************************/
393 |
394 | static char const *itosdef(
395 | int v,
396 | struct int_string_map const *pitab,
397 | size_t itabcnt,
398 | char const *def
399 | )
400 | {
401 | struct int_string_map *pism;
402 |
403 | assert(v >= 0);
404 | assert(pitab != NULL);
405 | assert(itabcnt > 0);
406 | assert(def != NULL);
407 |
408 | pism = bsearch(&v,pitab,itabcnt,sizeof(struct int_string_map),intstr_cmp);
409 | if (pism)
410 | return pism->text;
411 | else
412 | return def;
413 | }
414 |
415 | /********************************************************************/
416 |
417 | static int stoidef(
418 | char const *tag,
419 | struct string_int_map const *pstab,
420 | size_t stabcnt,
421 | int def
422 | )
423 | {
424 | struct string_int_map *psim;
425 | size_t len = strlen(tag) + 1;
426 | char buffer[16];
427 | size_t max = len > 15 ? 15 : len;
428 |
429 | memset(buffer,0,sizeof(buffer));
430 |
431 | for (size_t i = 0 ; i < max ; i++)
432 | buffer[i] = toupper(tag[i]);
433 |
434 | psim = bsearch(buffer,pstab,stabcnt,sizeof(struct string_int_map),strint_cmp);
435 | if (psim)
436 | return psim->value;
437 | else
438 | return def;
439 | }
440 |
441 | /*******************************************************************/
442 |
443 | char const *dns_rcode_enum(dns_rcode_t r)
444 | {
445 | return itosdef(r,c_dns_rcode_enum,RCODE_COUNT,"X-UNKN");
446 | }
447 |
448 | /*******************************************************************/
449 |
450 | char const *dns_rcode_text(dns_rcode_t r)
451 | {
452 | return itosdef(r,cm_dns_rcode,RCODE_COUNT,"Unknown error");
453 | }
454 |
455 | /*********************************************************************/
456 |
457 | char const *dns_type_text(dns_type_t t)
458 | {
459 | return itosdef(t,cm_dns_type,TYPE_COUNT,"X-UNKN");
460 | }
461 |
462 | /**********************************************************************/
463 |
464 | char const *dns_class_text(dns_class_t c)
465 | {
466 | return itosdef(c,cm_dns_class,CLASS_COUNT,"X-UNKN");
467 | }
468 |
469 | /*******************************************************************/
470 |
471 | char const *dns_op_text(dns_op_t o)
472 | {
473 | return itosdef(o,cm_dns_op,OP_COUNT,"X-UNKNOWN");
474 | }
475 |
476 | /********************************************************************/
477 |
478 | dns_rcode_t dns_rcode_value(char const *tag)
479 | {
480 | return stoidef(tag,cm_dns_rcode_is,RCODE_COUNT,RCODE_NOT_IMPLEMENTED);
481 | }
482 |
483 | /********************************************************************/
484 |
485 | dns_type_t dns_type_value(char const *tag)
486 | {
487 | return stoidef(tag,cm_dns_type_is,TYPE_COUNT,RR_UNKNOWN);
488 | }
489 |
490 | /*********************************************************************/
491 |
492 | dns_class_t dns_class_value(char const *tag)
493 | {
494 | return stoidef(tag,cm_dns_class_is,CLASS_COUNT,CLASS_UNKNOWN);
495 | }
496 |
497 | /**********************************************************************/
498 |
499 | dns_op_t dns_op_value(char const *tag)
500 | {
501 | return stoidef(tag,cm_dns_op_is,OP_COUNT,OP_UNKNOWN);
502 | }
503 |
504 | /**********************************************************************/
505 |
--------------------------------------------------------------------------------
/src/mappings.h:
--------------------------------------------------------------------------------
1 | /*************************************************************************
2 | *
3 | * Copyright 2010 by Sean Conner. All Rights Reserved.
4 | *
5 | * This library is free software; you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published by
7 | * the Free Software Foundation; either version 3 of the License, or (at your
8 | * option) any later version.
9 | *
10 | * This library is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
13 | * License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this library; if not, see .
17 | *
18 | **************************************************************************/
19 |
20 | /**************************************************************************
21 | *
22 | * Useful routines to convert error codes, RR, Class and Opcode values into
23 | * strings, and strings into their equivilent RR, Class or Opcode values.
24 | *
25 | * This file assumes C99. You must include the following files before
26 | * including this one:
27 | *
28 | * #include "dns.h"
29 | *
30 | **************************************************************************/
31 |
32 | #ifndef I_E2A4214D_2476_5EA3_92C1_9E450F8F349E
33 | #define I_E2A4214D_2476_5EA3_92C1_9E450F8F349E
34 |
35 | #ifdef __cplusplus
36 | extern "C" {
37 | #endif
38 |
39 | #ifndef __GNUC__
40 | # define __attribute__(x)
41 | #endif
42 |
43 | struct int_string_map
44 | {
45 | int const value;
46 | char const *const text;
47 | };
48 |
49 | extern struct int_string_map const c_dns_rcode_enum[];
50 |
51 | extern char const *dns_rcode_enum (dns_rcode_t) __attribute__ ((pure,nothrow));
52 | extern char const *dns_rcode_text (dns_rcode_t) __attribute__ ((pure,nothrow));
53 | extern char const *dns_type_text (dns_type_t) __attribute__ ((pure,nothrow));
54 | extern char const *dns_class_text (dns_class_t) __attribute__ ((pure,nothrow));
55 | extern char const *dns_op_text (dns_op_t) __attribute__ ((pure,nothrow));
56 |
57 | extern dns_rcode_t dns_rcode_value (char const *) __attribute__ ((pure,nothrow,nonnull));
58 | extern dns_type_t dns_type_value (char const *) __attribute__ ((pure,nothrow,nonnull));
59 | extern dns_class_t dns_class_value (char const *) __attribute__ ((pure,nothrow,nonnull));
60 | extern dns_op_t dns_op_value (char const *) __attribute__ ((pure,nothrow,nonnull));
61 |
62 | #ifdef __cplusplus
63 | }
64 | #endif
65 | #endif
66 |
--------------------------------------------------------------------------------
/src/netsimple.c:
--------------------------------------------------------------------------------
1 | /*************************************************************************
2 | *
3 | * Copyright 2010 by Sean Conner. All Rights Reserved.
4 | *
5 | * This library is free software; you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published by
7 | * the Free Software Foundation; either version 3 of the License, or (at your
8 | * option) any later version.
9 | *
10 | * This library is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
13 | * License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this library; if not, see .
17 | *
18 | **************************************************************************/
19 |
20 | /*********************************************************************
21 | *
22 | * Implementation of the simple network interface for DNS queries. Two
23 | * functions are exported:
24 | *
25 | * net_server()
26 | *
27 | * decode the IP address (IPv4/IPv6) from a text representation
28 | * to a network format.
29 | *
30 | * net_request()
31 | *
32 | * Send a request to the given server and wait a reponse. This
33 | * function is stupid simple---it opens a socket, sends the
34 | * request via sendto(), waits for up to 15 seconds for a
35 | * reply. If no reply is seen in 15 seconds, close the socket
36 | * and return an error---otherwise, call recvfrom(), close the
37 | * socket and return the data.
38 | *
39 | * Like I said, stupid simple. It's enough for testing and
40 | * very simple programs.
41 | *
42 | * This code is written for C99.
43 | *
44 | **************************************************************************/
45 |
46 | #include
47 | #include
48 | #include
49 |
50 | #include
51 | #include
52 |
53 | #include "dns.h"
54 | #include "netsimple.h"
55 |
56 | /************************************************************************/
57 |
58 | int net_server(
59 | sockaddr_all *addr,
60 | char const *host
61 | )
62 | {
63 | assert(addr != NULL);
64 | assert(host != NULL);
65 |
66 | memset(addr,0,sizeof(sockaddr_all));
67 |
68 | if (inet_pton(AF_INET,host,&addr->sin.sin_addr.s_addr) < 0)
69 | {
70 | if (inet_pton(AF_INET6,host,&addr->sin6.sin6_addr.s6_addr) < 0)
71 | return errno;
72 | addr->sin6.sin6_family = AF_INET6;
73 | addr->sin6.sin6_port = htons(53);
74 | }
75 | else
76 | {
77 | addr->sin.sin_family = AF_INET;
78 | addr->sin.sin_port = htons(53);
79 | }
80 |
81 | return 0;
82 | }
83 |
84 | /************************************************************************/
85 |
86 | int net_request(
87 | sockaddr_all *srvaddr,
88 | dns_packet_t *dest,
89 | size_t *dsize,
90 | dns_packet_t const *src,
91 | size_t ssize
92 | )
93 | {
94 | struct pollfd polldat;
95 | socklen_t asize;
96 | ssize_t bytes;
97 | int sock;
98 | int rc;
99 | int err;
100 |
101 | switch(srvaddr->sa.sa_family)
102 | {
103 | case AF_INET: asize = sizeof(struct sockaddr_in); break;
104 | case AF_INET6: asize = sizeof(struct sockaddr_in6); break;
105 | default: assert(0); return EPROTOTYPE;
106 | }
107 |
108 | sock = socket(srvaddr->sa.sa_family,SOCK_DGRAM,0);
109 | if (sock < 0)
110 | return errno;
111 |
112 | bytes = sendto(sock,src,ssize,0,&srvaddr->sa,asize);
113 | if (bytes < 0)
114 | {
115 | err = errno;
116 | close(sock);
117 | return err;
118 | }
119 |
120 | polldat.fd = sock;
121 | polldat.events = POLLIN;
122 |
123 | rc = poll(&polldat,1,15000);
124 | if (rc < 0)
125 | {
126 | err = errno;
127 | close(sock);
128 | return err;
129 | }
130 |
131 | if (rc == 0)
132 | {
133 | close(sock);
134 | return ETIMEDOUT;
135 | }
136 |
137 | bytes = recvfrom(sock,dest,*dsize,0,NULL,NULL);
138 | if (bytes < 0)
139 | {
140 | int err = errno;
141 | close(sock);
142 | return err;
143 | }
144 |
145 | *dsize = bytes;
146 | close(sock);
147 | return 0;
148 | }
149 |
150 | /**************************************************************************/
151 |
--------------------------------------------------------------------------------
/src/netsimple.h:
--------------------------------------------------------------------------------
1 | /*************************************************************************
2 | *
3 | * Copyright 2010 by Sean Conner. All Rights Reserved.
4 | *
5 | * This library is free software; you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published by
7 | * the Free Software Foundation; either version 3 of the License, or (at your
8 | * option) any later version.
9 | *
10 | * This library is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
13 | * License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this library; if not, see .
17 | *
18 | **************************************************************************/
19 |
20 | /************************************************************************
21 | *
22 | * Definitions for a simple network interface to send and receive DNS
23 | * queries.
24 | *
25 | * This only suffices for simple applications; for anything that does a lot
26 | * of DNS queries, you probably want to use something else.
27 | *
28 | * This file assumes C99. You must include the following files before
29 | * including this one:
30 | *
31 | * #include
32 | * #include
33 | * #include
34 | *
35 | * And if you want to decode the return values (beyond success/failure):
36 | *
37 | * #include
38 | *
39 | *************************************************************************/
40 |
41 | #ifndef I_927898DC_135D_5C61_B435_21EC89A06D2D
42 | #define I_927898DC_135D_5C61_B435_21EC89A06D2D
43 |
44 | #ifdef __cplusplus
45 | extern "C" {
46 | #endif
47 |
48 | #ifndef __GNUC__
49 | # define __attribute__(x)
50 | #endif
51 |
52 | typedef union sockaddr_all
53 | {
54 | struct sockaddr sa;
55 | struct sockaddr_in sin;
56 | struct sockaddr_in6 sin6;
57 | } sockaddr_all;
58 |
59 | extern int net_server (sockaddr_all *,char const *) __attribute__ ((nonnull));
60 | extern int net_request(sockaddr_all *,dns_packet_t *,size_t *,dns_packet_t const *,size_t) __attribute__ ((nonnull(1,2,3,4)));
61 |
62 | #ifdef __cplusplus
63 | }
64 | #endif
65 | #endif
66 |
--------------------------------------------------------------------------------
/src/output.c:
--------------------------------------------------------------------------------
1 | /*************************************************************************
2 | *
3 | * Copyright 2010 by Sean Conner. All Rights Reserved.
4 | *
5 | * This library is free software; you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published by
7 | * the Free Software Foundation; either version 3 of the License, or (at your
8 | * option) any later version.
9 | *
10 | * This library is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
13 | * License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this library; if not, see .
17 | *
18 | **************************************************************************/
19 |
20 | /**********************************************************************
21 | *
22 | * DNS record output functions used by sample application.
23 | *
24 | * It was factored out so it could be called from client applications.
25 | *
26 | ***************************************************************************/
27 |
28 | #include
29 | #include
30 |
31 | #include "dns.h"
32 | #include "mappings.h"
33 | #include "output.h"
34 |
35 | /************************************************************************/
36 |
37 | void dns_print_result(dns_query_t* presult)
38 | {
39 | /*-------------------------------------------
40 | ; Print the results out, ala dig
41 | ;-------------------------------------------*/
42 |
43 | dns_print_header(presult);
44 | dns_print_question("QUESTIONS" ,presult->questions ,presult->qdcount);
45 | dns_print_answer ("ANSWERS" ,presult->answers ,presult->ancount);
46 | dns_print_answer ("NAMESERVERS" ,presult->nameservers ,presult->nscount);
47 | dns_print_answer ("ADDITIONAL" ,presult->additional ,presult->arcount);
48 | }
49 |
50 | /************************************************************************/
51 |
52 | void dns_print_header(dns_query_t* presult)
53 | {
54 | printf(
55 | "; Questions = %lu\n"
56 | "; Answers = %lu\n"
57 | "; Name Servers = %lu\n"
58 | "; Additional Records = %lu\n"
59 | "; Authoritative Result = %s\n"
60 | "; Truncated Result = %s\n"
61 | "; Recursion Desired = %s\n"
62 | "; Recursion Available = %s\n"
63 | "; Authentic Data = %s\n"
64 | "; Checking disabled = %s\n"
65 | "; Result = %s\n",
66 | (unsigned long)presult->qdcount,
67 | (unsigned long)presult->ancount,
68 | (unsigned long)presult->nscount,
69 | (unsigned long)presult->arcount,
70 | presult->aa ? "true" : "false",
71 | presult->tc ? "true" : "false",
72 | presult->rd ? "true" : "false",
73 | presult->ra ? "true" : "false",
74 | presult->ad ? "true" : "false",
75 | presult->cd ? "true" : "false",
76 | dns_rcode_text(presult->rcode)
77 | );
78 | }
79 |
80 | /************************************************************************/
81 |
82 | void dns_print_question(char const *tag,dns_question_t *pquest,size_t cnt)
83 | {
84 | assert(tag != NULL);
85 | assert(pquest != NULL);
86 |
87 | printf("\n;;; %s\n\n",tag);
88 | for (size_t i = 0 ; i < cnt ; i++)
89 | {
90 | printf(
91 | ";%s %s %s\n",
92 | pquest[i].name,
93 | dns_class_text(pquest[i].class),
94 | dns_type_text (pquest[i].type)
95 | );
96 | }
97 | }
98 |
99 | /***********************************************************************/
100 |
101 | void dns_print_answer(char const *tag,dns_answer_t *pans,size_t cnt)
102 | {
103 | char ipaddr[INET6_ADDRSTRLEN];
104 |
105 | assert(tag != NULL);
106 | assert(pans != NULL);
107 |
108 | printf("\n;;; %s\n\n",tag);
109 |
110 | for (size_t i = 0 ; i < cnt ; i++)
111 | {
112 | if (pans[i].generic.type != RR_OPT)
113 | {
114 | printf(
115 | "%-16s\t%5lu\t%s\t%s\t",
116 | pans[i].generic.name,
117 | (unsigned long)pans[i].generic.ttl,
118 | dns_class_text(pans[i].generic.class),
119 | dns_type_text (pans[i].generic.type)
120 | );
121 | }
122 | else
123 | printf("; OPT RR");
124 |
125 | switch(pans[i].generic.type)
126 | {
127 | case RR_NS:
128 | printf("%s",pans[i].ns.nsdname);
129 | break;
130 | case RR_A:
131 | inet_ntop(AF_INET,&pans[i].a.address,ipaddr,sizeof(ipaddr));
132 | printf("%s",ipaddr);
133 | break;
134 | case RR_AAAA:
135 | inet_ntop(AF_INET6,&pans[i].aaaa.address,ipaddr,sizeof(ipaddr));
136 | printf("%s",ipaddr);
137 | break;
138 | case RR_CNAME:
139 | printf("%s",pans[i].cname.cname);
140 | break;
141 | case RR_MX:
142 | printf("%5d %s",pans[i].mx.preference,pans[i].mx.exchange);
143 | break;
144 | case RR_PTR:
145 | printf("%s",pans[i].ptr.ptr);
146 | break;
147 | case RR_HINFO:
148 | printf("\"%s\" \"%s\"",pans[i].hinfo.cpu,pans[i].hinfo.os);
149 | break;
150 | case RR_MINFO:
151 | printf("(\n\t\t\"%s\"\n\t\t\"%s\" )",pans[i].minfo.rmailbx,pans[i].minfo.emailbx);
152 | break;
153 | case RR_SPF:
154 | case RR_TXT:
155 | if (pans[i].txt.len < 30)
156 | printf("\"%s\"",pans[i].txt.text);
157 | else
158 | {
159 | size_t len;
160 | int max;
161 | size_t off;
162 |
163 | printf("(");
164 | len = pans[i].txt.len;
165 | off = 0;
166 |
167 | while(len)
168 | {
169 | max = (len > 64) ? 64 : (int)len;
170 | printf("\n\t\"%*.*s\"",max,max,&pans[i].txt.text[off]);
171 | off += max;
172 | len -= max;
173 | }
174 |
175 | printf("\n\t\t)\n");
176 | }
177 | break;
178 | case RR_SOA:
179 | printf(
180 | "%s %s (\n"
181 | "\t\t%10lu ; Serial\n"
182 | "\t\t%10lu ; Refresh\n"
183 | "\t\t%10lu ; Retry\n"
184 | "\t\t%10lu ; Expire\n"
185 | "\t\t%10lu ) ; Miminum\n",
186 | pans[i].soa.mname,
187 | pans[i].soa.rname,
188 | (unsigned long)pans[i].soa.serial,
189 | (unsigned long)pans[i].soa.refresh,
190 | (unsigned long)pans[i].soa.retry,
191 | (unsigned long)pans[i].soa.expire,
192 | (unsigned long)pans[i].soa.minimum
193 | );
194 | break;
195 | case RR_NAPTR:
196 | printf(
197 | "%5d %5d (\n"
198 | "\t\t\"%s\"\n"
199 | "\t\t\"%s\"\n"
200 | "\t\t\"%s\"\n"
201 | "\t\t%s )\n",
202 | pans[i].naptr.order,
203 | pans[i].naptr.preference,
204 | pans[i].naptr.flags,
205 | pans[i].naptr.services,
206 | pans[i].naptr.regexp,
207 | pans[i].naptr.replacement
208 | );
209 | break;
210 | case RR_LOC:
211 | printf(
212 | "(\n"
213 | "\t\t%3d %2d %2d %s ; Latitude\n"
214 | "\t\t%3d %2d %2d %s ; Longitude\n"
215 | "\t\t%11ld ; Altitude\n"
216 | "\t\t%11llu ; Size\n"
217 | "\t\t%11llu ; Horizontal Precision\n"
218 | "\t\t%11llu ; Vertical Precision\n"
219 | "\t\t)\n",
220 | pans[i].loc.latitude.deg,
221 | pans[i].loc.latitude.min,
222 | pans[i].loc.latitude.sec,
223 | pans[i].loc.latitude.nw ? "N" : "S",
224 | pans[i].loc.longitude.deg,
225 | pans[i].loc.longitude.min,
226 | pans[i].loc.longitude.sec,
227 | pans[i].loc.longitude.nw ? "W" : "E",
228 | pans[i].loc.altitude,
229 | pans[i].loc.size,
230 | pans[i].loc.horiz_pre,
231 | pans[i].loc.vert_pre
232 | );
233 | break;
234 | case RR_SRV:
235 | printf(
236 | "%5d %5d %5d %s",
237 | pans[i].srv.priority,
238 | pans[i].srv.weight,
239 | pans[i].srv.port,
240 | pans[i].srv.target
241 | );
242 | break;
243 | case RR_OPT:
244 | printf(
245 | "\n"
246 | ";\tpayload = %lu\n"
247 | ";\tDO = %s\n"
248 | ";\t#opts = %lu\n",
249 | (unsigned long)pans[i].opt.udp_payload,
250 | pans[i].opt.fdo ? "true" : "false",
251 | (unsigned long)pans[i].opt.numopts
252 | );
253 | break;
254 |
255 | default:
256 | break;
257 | }
258 | printf("\n");
259 | }
260 | }
261 |
262 | /**********************************************************************/
263 |
264 | #define LINESIZE 16
265 |
266 | void dns_dump_memory(FILE *out,void const *data,size_t size,size_t offset)
267 | {
268 | unsigned char const *block = data;
269 | char ascii[LINESIZE + 1];
270 | int skip;
271 | int j;
272 |
273 | assert(out != NULL);
274 | assert(block != NULL);
275 | assert(size > 0);
276 |
277 | while(size > 0)
278 | {
279 | fprintf(out,"%08lX: ",(unsigned long)offset);
280 |
281 | for (skip = offset % LINESIZE , j = 0 ; skip ; j++ , skip--)
282 | {
283 | fputs(" ",out);
284 | ascii[j] = ' ';
285 | }
286 |
287 | do
288 | {
289 | fprintf(out,"%02x ",*block);
290 | if (isprint(*block))
291 | ascii[j] = *block;
292 | else
293 | ascii[j] = '.';
294 |
295 | block++;
296 | offset++;
297 | j++;
298 | size--;
299 | } while((j < LINESIZE) && (size > 0));
300 |
301 | ascii[j] = '\0';
302 |
303 | if (j < LINESIZE)
304 | {
305 | int i;
306 |
307 | for (i = j ; i < LINESIZE ; i++)
308 | fputs(" ",out);
309 | }
310 | fprintf(out,"%s\n",ascii);
311 | }
312 | }
313 |
314 | /**********************************************************************/
315 |
--------------------------------------------------------------------------------
/src/output.h:
--------------------------------------------------------------------------------
1 | /*************************************************************************
2 | *
3 | * Copyright 2010 by Sean Conner. All Rights Reserved.
4 | *
5 | * This library is free software; you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published by
7 | * the Free Software Foundation; either version 3 of the License, or (at your
8 | * option) any later version.
9 | *
10 | * This library is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
13 | * License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this library; if not, see .
17 | *
18 | **************************************************************************/
19 |
20 | /**********************************************************************
21 | *
22 | * Definitions for DNS record output functions used by sample application.
23 | *
24 | * It was factored out so it could be called from client applications.
25 | *
26 | ***************************************************************************/
27 |
28 | #ifndef I_54636A09_9D2A_5B69_A900_EC8C8A59E060
29 | #define I_54636A09_9D2A_5B69_A900_EC8C8A59E060
30 |
31 | #ifdef __cplusplus
32 | extern "C" {
33 | #endif
34 |
35 | #ifndef __GNUC__
36 | # define __attribute__(x)
37 | #endif
38 |
39 | #include
40 | #include "dns.h"
41 |
42 | extern void dns_print_result (dns_query_t *);
43 | extern void dns_print_header (dns_query_t *);
44 | extern void dns_print_question (char const *,dns_question_t *,size_t);
45 | extern void dns_print_answer (char const *,dns_answer_t *,size_t);
46 | extern void dns_dump_memory (FILE *,void const *,size_t,size_t);
47 |
48 | #ifdef __cplusplus
49 | }
50 | #endif
51 | #endif
52 |
--------------------------------------------------------------------------------